Merge branch 'main' into Marshall-LICENSE-update
commit
75a6c6e2af
|
@ -0,0 +1,6 @@
|
||||||
|
##########################################
|
||||||
|
# code ownership
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
# default ownership:
|
||||||
|
* @zblurx @Marshall-Hallenbeck @NeffIsBack
|
|
@ -1,11 +1,8 @@
|
||||||
name: CrackMapExec Tests
|
name: CrackMapExec Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
pull_request_review:
|
||||||
push:
|
types: [submitted]
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
name: CrackMapExec Tests & Build
|
name: CrackMapExec Build Binaries
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
branches: [ main ]
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -24,7 +24,8 @@ def gen_cli_args():
|
||||||
\______|| _| `._____|/__/ \__\ \______||__|\__\ |__| |__| /__/ \__\ | _| |_______|/__/ \__\ |_______| \______|
|
\______|| _| `._____|/__/ \__\ \______||__|\__\ |__| |__| /__/ \__\ | _| |_______|/__/ \__\ |_______| \______|
|
||||||
|
|
||||||
A swiss army knife for pentesting networks
|
A swiss army knife for pentesting networks
|
||||||
Forged by @byt3bl33d3r and @mpgn_x64 using the powah of dank memes
|
Forged by @byt3bl33d3r and @mpgn_x64 using the powah of dank memes.
|
||||||
|
Maintained as an open source project by @NeffIsBack, @MJHallenbeck, @_zblurx
|
||||||
|
|
||||||
{highlight('Version', 'red')} : {highlight(VERSION)}
|
{highlight('Version', 'red')} : {highlight(VERSION)}
|
||||||
{highlight('Codename', 'red')}: {highlight(CODENAME)}
|
{highlight('Codename', 'red')}: {highlight(CODENAME)}
|
||||||
|
|
|
@ -144,7 +144,7 @@ class CMEModule:
|
||||||
return connection.execute("powershell.exe -e {} -OutputFormat Text".format(psScipt_b64), True)
|
return connection.execute("powershell.exe -e {} -OutputFormat Text".format(psScipt_b64), True)
|
||||||
|
|
||||||
def printCreds(self, context, output):
|
def printCreds(self, context, output):
|
||||||
# Format ouput if returned in some XML Format
|
# Format output if returned in some XML Format
|
||||||
if "CLIXML" in output:
|
if "CLIXML" in output:
|
||||||
output = self.stripXmlOutput(context, output)
|
output = self.stripXmlOutput(context, output)
|
||||||
|
|
||||||
|
|
|
@ -734,8 +734,9 @@ class smb(connection):
|
||||||
self.kdcHost,
|
self.kdcHost,
|
||||||
self.hash,
|
self.hash,
|
||||||
self.logger,
|
self.logger,
|
||||||
self.args.get_output_tries
|
self.args.get_output_tries,
|
||||||
) # self.args.share)
|
self.args.share
|
||||||
|
)
|
||||||
self.logger.info("Executed command via atexec")
|
self.logger.info("Executed command via atexec")
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -38,6 +38,8 @@ class TSCH_EXEC:
|
||||||
self.__doKerberos = doKerberos
|
self.__doKerberos = doKerberos
|
||||||
self.__kdcHost = kdcHost
|
self.__kdcHost = kdcHost
|
||||||
self.__tries = tries
|
self.__tries = tries
|
||||||
|
self.__output_filename = None
|
||||||
|
self.__share = share
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
if hashes is not None:
|
if hashes is not None:
|
||||||
|
@ -73,7 +75,7 @@ class TSCH_EXEC:
|
||||||
def output_callback(self, data):
|
def output_callback(self, data):
|
||||||
self.__outputBuffer = data
|
self.__outputBuffer = data
|
||||||
|
|
||||||
def gen_xml(self, command, tmpFileName, fileless=False):
|
def gen_xml(self, command, fileless=False):
|
||||||
xml = """<?xml version="1.0" encoding="UTF-16"?>
|
xml = """<?xml version="1.0" encoding="UTF-16"?>
|
||||||
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
||||||
<Triggers>
|
<Triggers>
|
||||||
|
@ -114,11 +116,12 @@ class TSCH_EXEC:
|
||||||
<Command>cmd.exe</Command>
|
<Command>cmd.exe</Command>
|
||||||
"""
|
"""
|
||||||
if self.__retOutput:
|
if self.__retOutput:
|
||||||
|
self.__output_filename = "\\Windows\\Temp\\" + gen_random_string(6)
|
||||||
if fileless:
|
if fileless:
|
||||||
local_ip = self.__rpctransport.get_socket().getsockname()[0]
|
local_ip = self.__rpctransport.get_socket().getsockname()[0]
|
||||||
argument_xml = f" <Arguments>/C {command} > \\\\{local_ip}\\{self.__share_name}\\{tmpFileName} 2>&1</Arguments>"
|
argument_xml = f" <Arguments>/C {command} > \\\\{local_ip}\\{self.__share_name}\\{self.__output_filename} 2>&1</Arguments>"
|
||||||
else:
|
else:
|
||||||
argument_xml = f" <Arguments>/C {command} > %windir%\\Temp\\{tmpFileName} 2>&1</Arguments>"
|
argument_xml = f" <Arguments>/C {command} > {self.__output_filename} 2>&1</Arguments>"
|
||||||
|
|
||||||
elif self.__retOutput is False:
|
elif self.__retOutput is False:
|
||||||
argument_xml = f" <Arguments>/C {command}</Arguments>"
|
argument_xml = f" <Arguments>/C {command}</Arguments>"
|
||||||
|
@ -143,9 +146,8 @@ class TSCH_EXEC:
|
||||||
# dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY)
|
# dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY)
|
||||||
|
|
||||||
tmpName = gen_random_string(8)
|
tmpName = gen_random_string(8)
|
||||||
tmpFileName = tmpName + ".tmp"
|
|
||||||
|
|
||||||
xml = self.gen_xml(command, tmpFileName, fileless)
|
xml = self.gen_xml(command, fileless)
|
||||||
|
|
||||||
self.logger.info(f"Task XML: {xml}")
|
self.logger.info(f"Task XML: {xml}")
|
||||||
taskCreated = False
|
taskCreated = False
|
||||||
|
@ -187,7 +189,7 @@ class TSCH_EXEC:
|
||||||
if fileless:
|
if fileless:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with open(os.path.join("/tmp", "cme_hosted", tmpFileName), "r") as output:
|
with open(os.path.join("/tmp", "cme_hosted", self.__output_filename), "r") as output:
|
||||||
self.output_callback(output.read())
|
self.output_callback(output.read())
|
||||||
break
|
break
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -198,15 +200,15 @@ class TSCH_EXEC:
|
||||||
tries = 1
|
tries = 1
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
self.logger.info(f"Attempting to read ADMIN$\\Temp\\{tmpFileName}")
|
self.logger.info(f"Attempting to read {self.__share}\\{self.__output_filename}")
|
||||||
smbConnection.getFile("ADMIN$", f"Temp\\{tmpFileName}", self.output_callback)
|
smbConnection.getFile(self.__share, self.__output_filename, self.output_callback)
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if tries >= self.__tries:
|
if tries >= self.__tries:
|
||||||
self.logger.fail(f'ATEXEC: Get output file error, maybe got detected by AV software, please increase the number of tries with the option "--get-output-tries". If it\'s still failing maybe something is blocking the schedule job, try another exec method')
|
self.logger.fail(f"ATEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option '--get-output-tries'. If it is still failing, try the 'wmi' protocol or another exec method")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
||||||
self.logger.fail(f'ATEXEC: Get ouput failed, target has blocked ADMIN$ access (maybe command executed!)')
|
self.logger.fail(f"ATEXEC: Getting the output file failed - target has blocked access to the share: {self.__share} (but the command may have executed!)")
|
||||||
break
|
break
|
||||||
if str(e).find("SHARING") > 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
if str(e).find("SHARING") > 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
@ -215,7 +217,7 @@ class TSCH_EXEC:
|
||||||
self.logger.debug(str(e))
|
self.logger.debug(str(e))
|
||||||
|
|
||||||
if self.__outputBuffer:
|
if self.__outputBuffer:
|
||||||
self.logger.debug(f"Deleting file ADMIN$\\Temp\\{tmpFileName}")
|
self.logger.debug(f"Deleting file {self.__share}\\{self.__output_filename}")
|
||||||
smbConnection.deleteFile("ADMIN$", f"Temp\\{tmpFileName}")
|
smbConnection.deleteFile(self.__share, self.__output_filename)
|
||||||
|
|
||||||
dce.disconnect()
|
dce.disconnect()
|
||||||
|
|
|
@ -252,10 +252,10 @@ class MMCEXEC:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if tries >= self.__tries:
|
if tries >= self.__tries:
|
||||||
self.logger.fail(f'MMCEXEC: Get output file error, maybe got detected by AV software, please increase the number of tries with the option "--get-output-tries". If it\'s still failing maybe something is blocking the schedule job, try another exec method')
|
self.logger.fail(f"MMCEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option '--get-output-tries'. If it is still failing, try the 'wmi' protocol or another exec method")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
||||||
self.logger.fail(f'MMCEXEC: Get ouput failed, target has blocked {self.__share} access (maybe command executed!)')
|
self.logger.fail(f"MMCEXEC: Getting the output file failed - target has blocked access to the share: {self.__share} (but the command may have executed!)")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
||||||
# Output not finished, let's wait
|
# Output not finished, let's wait
|
||||||
|
|
|
@ -91,7 +91,7 @@ def proto_args(parser, std_parser, module_parser):
|
||||||
help="force the PowerShell command to run in a 32-bit process")
|
help="force the PowerShell command to run in a 32-bit process")
|
||||||
cgroup.add_argument("--no-output", action="store_true", help="do not retrieve command output")
|
cgroup.add_argument("--no-output", action="store_true", help="do not retrieve command output")
|
||||||
cegroup = cgroup.add_mutually_exclusive_group()
|
cegroup = cgroup.add_mutually_exclusive_group()
|
||||||
cegroup.add_argument("-x", metavar="COMMAND", dest="execute", help="execute the specified command")
|
cegroup.add_argument("-x", metavar="COMMAND", dest="execute", help="execute the specified CMD command")
|
||||||
cegroup.add_argument("-X", metavar="PS_COMMAND", dest="ps_execute", help="execute the specified PowerShell command")
|
cegroup.add_argument("-X", metavar="PS_COMMAND", dest="ps_execute", help="execute the specified PowerShell command")
|
||||||
psgroup = smb_parser.add_argument_group("Powershell Obfuscation", "Options for PowerShell script obfuscation")
|
psgroup = smb_parser.add_argument_group("Powershell Obfuscation", "Options for PowerShell script obfuscation")
|
||||||
psgroup.add_argument("--obfs", action="store_true", help="Obfuscate PowerShell scripts")
|
psgroup.add_argument("--obfs", action="store_true", help="Obfuscate PowerShell scripts")
|
||||||
|
|
|
@ -170,10 +170,10 @@ class SMBEXEC:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if tries >= self.__tries:
|
if tries >= self.__tries:
|
||||||
self.logger.fail(f'SMBEXEC: Get output file error, maybe got detected by AV software, please increase the number of tries with the option "--get-output-tries". If it\'s still failing maybe something is blocking the schedule job, try another exec method')
|
self.logger.fail(f"SMBEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option '--get-output-tries'. If it is still failing, try the 'wmi' protocol or another exec method")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
||||||
self.logger.fail(f'SMBEXEC: Get ouput failed, target has blocked {self.__share} access (maybe command executed!)')
|
self.logger.fail(f"SMBEXEC: Getting the output file failed - target has blocked access to the share: {self.__share} (but the command may have executed!)")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
||||||
# Output not finished, let's wait
|
# Output not finished, let's wait
|
||||||
|
|
|
@ -166,10 +166,10 @@ class WMIEXEC:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if tries >= self.__tries:
|
if tries >= self.__tries:
|
||||||
self.logger.fail(f'WMIEXEC: Get output file error, maybe got detected by AV software, please increase the number of tries with the option "--get-output-tries". If it\'s still failing maybe something is blocking the schedule job, try another exec method')
|
self.logger.fail(f"WMIEXEC: Could not retrieve output file, it may have been detected by AV. If it is still failing, try the 'wmi' protocol or another exec method")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
if str(e).find("STATUS_BAD_NETWORK_NAME") >0 :
|
||||||
self.logger.fail(f'SMB connection: target has blocked {self.__share} access (maybe command executed!)')
|
self.logger.fail(f"SMB connection: target has blocked {self.__share} access (maybe command executed!)")
|
||||||
break
|
break
|
||||||
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
if str(e).find("STATUS_SHARING_VIOLATION") >= 0 or str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0:
|
||||||
sleep(2)
|
sleep(2)
|
||||||
|
|
|
@ -231,30 +231,13 @@ class winrm(connection):
|
||||||
self.password = password
|
self.password = password
|
||||||
self.username = username
|
self.username = username
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
if self.args.ssl and self.args.ignore_ssl_cert:
|
|
||||||
self.conn = Client(
|
self.conn = Client(
|
||||||
self.host,
|
self.host,
|
||||||
auth="ntlm",
|
auth="ntlm",
|
||||||
username=f"{domain}\\{self.username}",
|
username=f"{domain}\\{self.username}",
|
||||||
password=self.password,
|
password=self.password,
|
||||||
ssl=True,
|
ssl=True if self.args.ssl else False,
|
||||||
cert_validation=False,
|
cert_validation=False if self.args.ignore_ssl_cert else True,
|
||||||
)
|
|
||||||
elif self.args.ssl:
|
|
||||||
self.conn = Client(
|
|
||||||
self.host,
|
|
||||||
auth="ntlm",
|
|
||||||
username=f"{domain}\\{self.username}",
|
|
||||||
password=self.password,
|
|
||||||
ssl=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.conn = Client(
|
|
||||||
self.host,
|
|
||||||
auth="ntlm",
|
|
||||||
username=f"{domain}\\{self.username}",
|
|
||||||
password=self.password,
|
|
||||||
ssl=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
||||||
|
@ -308,30 +291,13 @@ class winrm(connection):
|
||||||
nthash = self.hash
|
nthash = self.hash
|
||||||
|
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
if self.args.ssl and self.args.ignore_ssl_cert:
|
|
||||||
self.conn = Client(
|
self.conn = Client(
|
||||||
self.host,
|
self.host,
|
||||||
auth="ntlm",
|
auth="ntlm",
|
||||||
username=f"{self.domain}\\{self.username}",
|
username=f"{self.domain}\\{self.username}",
|
||||||
password=lmhash + nthash,
|
password=lmhash + nthash,
|
||||||
ssl=True,
|
ssl=True if self.args.ssl else False,
|
||||||
cert_validation=False,
|
cert_validation=False if self.args.ignore_ssl_cert else True,
|
||||||
)
|
|
||||||
elif self.args.ssl:
|
|
||||||
self.conn = Client(
|
|
||||||
self.host,
|
|
||||||
auth="ntlm",
|
|
||||||
username=f"{self.domain}\\{self.username}",
|
|
||||||
password=lmhash + nthash,
|
|
||||||
ssl=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.conn = Client(
|
|
||||||
self.host,
|
|
||||||
auth="ntlm",
|
|
||||||
username=f"{self.domain}\\{self.username}",
|
|
||||||
password=lmhash + nthash,
|
|
||||||
ssl=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
# TO DO: right now we're just running the hostname command to make the winrm library auth to the server
|
||||||
|
|
|
@ -170,7 +170,7 @@ class wmi(connection):
|
||||||
if "dcom" in locals():
|
if "dcom" in locals():
|
||||||
dcom.disconnect()
|
dcom.disconnect()
|
||||||
|
|
||||||
if not str(e).find("access_denied") > 0:
|
if "access_denied" not in str(e).lower():
|
||||||
self.logger.fail(str(e))
|
self.logger.fail(str(e))
|
||||||
else:
|
else:
|
||||||
if not flag or not self.stringBinding:
|
if not flag or not self.stringBinding:
|
||||||
|
@ -188,7 +188,7 @@ class wmi(connection):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
dcom.disconnect()
|
dcom.disconnect()
|
||||||
|
|
||||||
if not str(e).find("access_denied") > 0:
|
if "access_denied" not in str(e).lower():
|
||||||
self.logger.fail(str(e))
|
self.logger.fail(str(e))
|
||||||
else:
|
else:
|
||||||
dcom.disconnect()
|
dcom.disconnect()
|
||||||
|
@ -432,7 +432,7 @@ class wmi(connection):
|
||||||
if not self.args.no_output:
|
if not self.args.no_output:
|
||||||
get_output = True
|
get_output = True
|
||||||
|
|
||||||
if "systeminfo" in command and self.args.interval_time < 10:
|
if "systeminfo" in command and self.args.exec_timeout < 10:
|
||||||
self.logger.fail("Execute 'systeminfo' must set the interval time higher than 10 seconds")
|
self.logger.fail("Execute 'systeminfo' must set the interval time higher than 10 seconds")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -441,11 +441,11 @@ class wmi(connection):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.args.exec_method == "wmiexec":
|
if self.args.exec_method == "wmiexec":
|
||||||
exec_method = wmiexec.WMIEXEC(self.conn.getRemoteName(), self.username, self.password, self.domain, self.lmhash, self.nthash, self.doKerberos, self.kdcHost, self.aesKey, self.logger, self.args.interval_time, self.args.codec)
|
exec_method = wmiexec.WMIEXEC(self.conn.getRemoteName(), self.username, self.password, self.domain, self.lmhash, self.nthash, self.doKerberos, self.kdcHost, self.aesKey, self.logger, self.args.exec_timeout, self.args.codec)
|
||||||
output = exec_method.execute(command, get_output)
|
output = exec_method.execute(command, get_output)
|
||||||
|
|
||||||
elif self.args.exec_method == "wmiexec-event":
|
elif self.args.exec_method == "wmiexec-event":
|
||||||
exec_method = wmiexec_event.WMIEXEC_EVENT(self.conn.getRemoteName(), self.username, self.password, self.domain, self.lmhash, self.nthash, self.doKerberos, self.kdcHost, self.aesKey, self.logger, self.args.interval_time, self.args.codec)
|
exec_method = wmiexec_event.WMIEXEC_EVENT(self.conn.getRemoteName(), self.username, self.password, self.domain, self.lmhash, self.nthash, self.doKerberos, self.kdcHost, self.aesKey, self.logger, self.args.exec_timeout, self.args.codec)
|
||||||
output = exec_method.execute(command, get_output)
|
output = exec_method.execute(command, get_output)
|
||||||
|
|
||||||
self.conn.disconnect()
|
self.conn.disconnect()
|
||||||
|
|
|
@ -23,7 +23,7 @@ def proto_args(parser, std_parser, module_parser):
|
||||||
"[wmiexec (win32_process + StdRegProv)]: get command results over registry instead of using smb connection. "
|
"[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, "
|
"[wmiexec-event (T1546.003)]: this method is not very stable, highly recommend use this method in single host, "
|
||||||
"using on multiple hosts may crash (just try again if it crashed).")
|
"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("--exec-timeout", default=5, metavar='exec_timeout', dest='exec_timeout', type=int, help='Set timeout (in seconds) when executing a command, minimum 5 seconds is recommended. Default: %(default)s')
|
||||||
cgroup.add_argument("--codec", default="utf-8",
|
cgroup.add_argument("--codec", default="utf-8",
|
||||||
help="Set encoding used (codec) from the target's output (default "
|
help="Set encoding used (codec) from the target's output (default "
|
||||||
"\"utf-8\"). If errors are detected, run chcp.com at the target, "
|
"\"utf-8\"). If errors are detected, run chcp.com at the target, "
|
||||||
|
|
|
@ -34,7 +34,7 @@ from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||||
from impacket.dcerpc.v5.dcom.wmi import CLSID_WbemLevel1Login, IID_IWbemLevel1Login, WBEM_FLAG_FORWARD_ONLY, IWbemLevel1Login
|
from impacket.dcerpc.v5.dcom.wmi import CLSID_WbemLevel1Login, IID_IWbemLevel1Login, WBEM_FLAG_FORWARD_ONLY, IWbemLevel1Login
|
||||||
|
|
||||||
class WMIEXEC:
|
class WMIEXEC:
|
||||||
def __init__(self, host, username, password, domain, lmhash, nthash, doKerberos, kdcHost, aesKey, logger, interval_time, codec):
|
def __init__(self, host, username, password, domain, lmhash, nthash, doKerberos, kdcHost, aesKey, logger, exec_timeout, codec):
|
||||||
self.__host = host
|
self.__host = host
|
||||||
self.__username = username
|
self.__username = username
|
||||||
self.__password = password
|
self.__password = password
|
||||||
|
@ -45,7 +45,7 @@ class WMIEXEC:
|
||||||
self.__kdcHost = kdcHost
|
self.__kdcHost = kdcHost
|
||||||
self.__aesKey = aesKey
|
self.__aesKey = aesKey
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.__interval_time = interval_time
|
self.__exec_timeout = exec_timeout
|
||||||
self.__registry_Path = ""
|
self.__registry_Path = ""
|
||||||
self.__outputBuffer = ""
|
self.__outputBuffer = ""
|
||||||
self.__retOutput = True
|
self.__retOutput = True
|
||||||
|
@ -91,8 +91,8 @@ class WMIEXEC:
|
||||||
command = fr'''{self.__shell} {command} 1> {result_output} 2>&1 && certutil -encodehex -f {result_output} {result_output_b64} 0x40000001 && for /F "usebackq" %G in ("{result_output_b64}") do reg add HKLM\{self.__registry_Path} /v {keyName} /t REG_SZ /d "%G" /f && del /q /f /s {result_output} {result_output_b64}'''
|
command = fr'''{self.__shell} {command} 1> {result_output} 2>&1 && certutil -encodehex -f {result_output} {result_output_b64} 0x40000001 && for /F "usebackq" %G in ("{result_output_b64}") do reg add HKLM\{self.__registry_Path} /v {keyName} /t REG_SZ /d "%G" /f && del /q /f /s {result_output} {result_output_b64}'''
|
||||||
|
|
||||||
self.execute_remote(command)
|
self.execute_remote(command)
|
||||||
self.logger.info("Waiting {}s for command completely executed.".format(self.__interval_time))
|
self.logger.info("Waiting {}s for command completely executed.".format(self.__exec_timeout))
|
||||||
time.sleep(self.__interval_time)
|
time.sleep(self.__exec_timeout)
|
||||||
|
|
||||||
self.queryRegistry(keyName)
|
self.queryRegistry(keyName)
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class WMIEXEC:
|
||||||
retVal = descriptor.GetStringValue(2147483650, self.__registry_Path, keyName)
|
retVal = descriptor.GetStringValue(2147483650, self.__registry_Path, keyName)
|
||||||
self.__outputBuffer = base64.b64decode(retVal.sValue).decode(self.__codec, errors='replace').rstrip('\r\n')
|
self.__outputBuffer = base64.b64decode(retVal.sValue).decode(self.__codec, errors='replace').rstrip('\r\n')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.fail(f'WMIEXEC: Get output file error, maybe command not executed successfully or got detected by AV software, please increase the interval time of command execution with "--interval-time" option. If it\'s still failing maybe something is blocking the schedule job in vbscript, try another exec method')
|
self.logger.fail(f"WMIEXEC: Could not retrieve output file, it may have been detected by AV. Please try increasing the timeout with the '--exec-timeout' option. If it is still failing, try the 'smb' protocol or another exec method")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logger.debug(f"Removing temporary registry path: HKLM\\{self.__registry_Path}")
|
self.logger.debug(f"Removing temporary registry path: HKLM\\{self.__registry_Path}")
|
||||||
|
|
|
@ -37,7 +37,7 @@ from impacket.dcerpc.v5.dcom.wmi import WBEMSTATUS
|
||||||
from impacket.dcerpc.v5.dcom.wmi import CLSID_WbemLevel1Login, IID_IWbemLevel1Login, WBEM_FLAG_FORWARD_ONLY, IWbemLevel1Login, WBEMSTATUS
|
from impacket.dcerpc.v5.dcom.wmi import CLSID_WbemLevel1Login, IID_IWbemLevel1Login, WBEM_FLAG_FORWARD_ONLY, IWbemLevel1Login, WBEMSTATUS
|
||||||
|
|
||||||
class WMIEXEC_EVENT:
|
class WMIEXEC_EVENT:
|
||||||
def __init__(self, host, username, password, domain, lmhash, nthash, doKerberos, kdcHost, aesKey, logger, interval_time, codec):
|
def __init__(self, host, username, password, domain, lmhash, nthash, doKerberos, kdcHost, aesKey, logger, exec_timeout, codec):
|
||||||
self.__host = host
|
self.__host = host
|
||||||
self.__username = username
|
self.__username = username
|
||||||
self.__password = password
|
self.__password = password
|
||||||
|
@ -51,7 +51,7 @@ class WMIEXEC_EVENT:
|
||||||
self.__retOutput = True
|
self.__retOutput = True
|
||||||
|
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.__interval_time = interval_time
|
self.__exec_timeout = exec_timeout
|
||||||
self.__codec = codec
|
self.__codec = codec
|
||||||
self.__instanceID = f"windows-object-{str(uuid.uuid4())}"
|
self.__instanceID = f"windows-object-{str(uuid.uuid4())}"
|
||||||
self.__instanceID_StoreResult = f"windows-object-{str(uuid.uuid4())}"
|
self.__instanceID_StoreResult = f"windows-object-{str(uuid.uuid4())}"
|
||||||
|
@ -84,8 +84,8 @@ class WMIEXEC_EVENT:
|
||||||
self.execute_remote(command)
|
self.execute_remote(command)
|
||||||
|
|
||||||
# Get command results
|
# Get command results
|
||||||
self.logger.info("Waiting {}s for command completely executed.".format(self.__interval_time))
|
self.logger.info("Waiting {}s for command completely executed.".format(self.__exec_timeout))
|
||||||
time.sleep(self.__interval_time)
|
time.sleep(self.__exec_timeout)
|
||||||
|
|
||||||
if self.__retOutput:
|
if self.__retOutput:
|
||||||
self.get_CommandResult()
|
self.get_CommandResult()
|
||||||
|
@ -190,7 +190,7 @@ class WMIEXEC_EVENT:
|
||||||
record = dict(command_ResultObject.getProperties())
|
record = dict(command_ResultObject.getProperties())
|
||||||
self.__outputBuffer = base64.b64decode(record['ScriptText']['value']).decode(self.__codec, errors='replace')
|
self.__outputBuffer = base64.b64decode(record['ScriptText']['value']).decode(self.__codec, errors='replace')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.fail(f'WMIEXEC-EVENT: Get output file error, maybe command not executed successfully or got detected by AV software, please increase the interval time of command execution with "--interval-time" option. If it\'s still failing maybe something is blocking the schedule job in vbscript, try another exec method')
|
self.logger.fail(f"WMIEXEC-EVENT: Could not retrieve output file, it may have been detected by AV. Please try increasing the timeout with the '--exec-timeout' option. If it is still failing, try the 'smb' protocol or another exec method")
|
||||||
|
|
||||||
def remove_Instance(self):
|
def remove_Instance(self):
|
||||||
if self.__retOutput:
|
if self.__retOutput:
|
||||||
|
|
|
@ -853,9 +853,8 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "impacket"
|
name = "impacket"
|
||||||
version = "0.12.0.dev1+20230816.160145.f6e03b99"
|
version = "0.12.0.dev1+20230909.154612.3beeda7c"
|
||||||
description = "Network protocols Constructors and Dissectors"
|
description = "Network protocols Constructors and Dissectors"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = []
|
files = []
|
||||||
|
@ -878,7 +877,7 @@ six = "*"
|
||||||
type = "git"
|
type = "git"
|
||||||
url = "https://github.com/mpgn/impacket.git"
|
url = "https://github.com/mpgn/impacket.git"
|
||||||
reference = "gkdi"
|
reference = "gkdi"
|
||||||
resolved_reference = "f6e03b99ce9da7f502a03488c8d26151236fa679"
|
resolved_reference = "3beeda7c3188936ed20f58c2c169430c2cfdfb1a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "importlib-metadata"
|
name = "importlib-metadata"
|
||||||
|
|
Loading…
Reference in New Issue