Skip to content

Commit 8426ec9

Browse files
authored
SMBServer & NTLMRelayx with IPv6 support (#2024)
* Adding IPv6 support to SMBServer * Adding IPv6 support to NTLMRelayX (should update after #2023 - utils.get_address() -) * Reusing utils.get_address to resolve the address on which each relay server will listen * Update smbserver.py Added a comment explaining why repeated code in SMBSERVER constructor * Setting right address family for relay servers (ipv6) * Fixing scope_id resolution in SMBSERVER class for IPv6
1 parent 40d8784 commit 8426ec9

File tree

9 files changed

+44
-26
lines changed

9 files changed

+44
-26
lines changed

examples/ntlmrelayx.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ def stop_servers(threads):
290290

291291
# Interface address specification
292292
parser.add_argument('-ip','--interface-ip', action='store', metavar='INTERFACE_IP', help='IP address of interface to '
293-
'bind SMB and HTTP servers',default='')
293+
'bind relay servers ("0.0.0.0" or "::" if omitted)',default=argparse.SUPPRESS)
294294

295295
serversoptions = parser.add_argument_group()
296296
serversoptions.add_argument('--no-smb-server', action='store_true', help='Disables the SMB server')
@@ -332,7 +332,7 @@ def stop_servers(threads):
332332
'setting the proxy host to the one supplied.')
333333
parser.add_argument('-wa','--wpad-auth-num', action='store', type=int, default=1, help='Prompt for authentication N times for clients without MS16-077 installed '
334334
'before serving a WPAD file. (default=1)')
335-
parser.add_argument('-6','--ipv6', action='store_true',help='Listen on both IPv6 and IPv4')
335+
parser.add_argument('-6','--ipv6', action='store_true',help='Listen on IPv6')
336336
parser.add_argument('--remove-mic', action='store_true',help='Remove MIC (exploit CVE-2019-1040)')
337337
parser.add_argument('--serve-image', action='store',help='local path of the image that will we returned to clients')
338338
parser.add_argument('-c', action='store', type=str, required=False, metavar = 'COMMAND', help='Command to execute on '
@@ -534,6 +534,9 @@ def stop_servers(threads):
534534
socks_thread.start()
535535
threads.add(socks_thread)
536536

537+
if 'interface_ip' not in options:
538+
options.interface_ip = '::' if options.ipv6 else '0.0.0.0'
539+
537540
c = start_servers(options, threads)
538541

539542
# Log multirelay flag status

examples/smbserver.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@
4242
parser.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes for the Username, format is LMHASH:NTHASH')
4343
parser.add_argument('-ts', action='store_true', help='Adds timestamp to every logging output')
4444
parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
45-
parser.add_argument('-ip', '--interface-address', action='store', default='0.0.0.0', help='ip address of listening interface')
45+
parser.add_argument('-ip', '--interface-address', action='store', default=argparse.SUPPRESS, help='ip address of listening interface ("0.0.0.0" or "::" if omitted)')
4646
parser.add_argument('-port', action='store', default='445', help='TCP port for listening incoming connections (default 445)')
4747
parser.add_argument('-dropssp', action='store_true', default=False, help='Disable NTLM ESS/SSP during negotiation')
48+
parser.add_argument('-6','--ipv6', action='store_true',help='Listen on IPv6')
4849
parser.add_argument('-smb2support', action='store_true', default=False, help='SMB2 Support (experimental!)')
4950
parser.add_argument('-outputfile', action='store', default=None, help='Output file to log smbserver output messages')
5051

@@ -65,7 +66,10 @@
6566
else:
6667
comment = options.comment
6768

68-
server = smbserver.SimpleSMBServer(listenAddress=options.interface_address, listenPort=int(options.port))
69+
if 'interface_address' not in options:
70+
options.interface_address = '::' if options.ipv6 else '0.0.0.0'
71+
72+
server = smbserver.SimpleSMBServer(listenAddress=options.interface_address, listenPort=int(options.port), ipv6=options.ipv6)
6973

7074
if options.outputfile:
7175
logging.info('Switching output to file %s' % options.outputfile)

impacket/examples/ntlmrelayx/servers/httprelayserver.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@
3333
from impacket.nt_errors import STATUS_ACCESS_DENIED, STATUS_SUCCESS
3434
from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor
3535
from impacket.examples.ntlmrelayx.servers.socksserver import activeConnections
36+
from impacket.examples.utils import get_address
3637

3738
class HTTPRelayServer(Thread):
3839

3940
class HTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
4041
def __init__(self, server_address, RequestHandlerClass, config):
4142
self.config = config
4243
self.daemon_threads = True
43-
if self.config.ipv6:
44-
self.address_family = socket.AF_INET6
44+
self.address_family, server_address = get_address(server_address[0], server_address[1], self.config.ipv6)
4545
# Tracks the number of times authentication was prompted for WPAD per client
4646
self.wpad_counters = {}
47-
socketserver.TCPServer.__init__(self,server_address, RequestHandlerClass)
47+
socketserver.TCPServer.__init__(self, server_address, RequestHandlerClass)
4848

4949
class HTTPHandler(http.server.SimpleHTTPRequestHandler):
5050
def __init__(self,request, client_address, server):

impacket/examples/ntlmrelayx/servers/rawrelayserver.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from impacket.nt_errors import STATUS_ACCESS_DENIED, STATUS_SUCCESS
3535
from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor
3636
from impacket.examples.ntlmrelayx.servers.socksserver import activeConnections
37+
from impacket.examples.utils import get_address
3738

3839

3940
class RAWRelayServer(Thread):
@@ -43,9 +44,7 @@ class RAWServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
4344
def __init__(self, server_address, RequestHandlerClass, config):
4445
self.config = config
4546
self.daemon_threads = True
46-
#if self.config.ipv6:
47-
# self.address_family = socket.AF_INET6
48-
47+
self.address_family, server_address = get_address(server_address[0], server_address[1], self.config.ipv6)
4948
socketserver.TCPServer.__init__(self, server_address, RequestHandlerClass)
5049

5150
class RAWHandler(socketserver.BaseRequestHandler):

impacket/examples/ntlmrelayx/servers/rpcrelayserver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@
2828
from impacket.nt_errors import ERROR_MESSAGES, STATUS_SUCCESS
2929
from impacket.examples.ntlmrelayx.utils.targetsutils import TargetsProcessor
3030
from impacket.examples.ntlmrelayx.servers.socksserver import activeConnections
31+
from impacket.examples.utils import get_address
3132

3233

3334
class RPCRelayServer(Thread):
3435
class RPCSocketServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
3536
def __init__(self, server_address, RequestHandlerClass, config):
3637
self.config = config
3738
self.daemon_threads = True
38-
if self.config.ipv6:
39-
self.address_family = socket.AF_INET6
39+
self.address_family, server_address = get_address(server_address[0], server_address[1], self.config.ipv6)
4040
socketserver.TCPServer.allow_reuse_address = True
4141
socketserver.TCPServer.__init__(self, server_address, RequestHandlerClass)
4242

impacket/examples/ntlmrelayx/servers/smbrelayserver.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,13 @@ def __init__(self,config):
106106
smbConfig.set('IPC$','share type','3')
107107
smbConfig.set('IPC$','path','')
108108

109-
# Change address_family to IPv6 if this is configured
110-
if self.config.ipv6:
111-
SMBSERVER.address_family = socket.AF_INET6
112-
113109
# changed to dereference configuration interfaceIp
114110
if self.config.listeningPort:
115111
smbport = self.config.listeningPort
116112
else:
117113
smbport = 445
118114

119-
self.server = SMBSERVER((config.interfaceIp,smbport), config_parser = smbConfig)
115+
self.server = SMBSERVER((config.interfaceIp,smbport), config_parser=smbConfig, ipv6=self.config.ipv6)
120116
if not self.config.disableMulti:
121117
self.server.setAuthCallback(auth_callback)
122118
logging.getLogger('impacket.smbserver').setLevel(logging.CRITICAL)

impacket/examples/ntlmrelayx/servers/wcfrelayserver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@
4343
from impacket.smbserver import outputToJohnFormat, writeJohnOutputToFile
4444
from impacket.spnego import SPNEGO_NegTokenInit, ASN1_AID, SPNEGO_NegTokenResp, TypesMech, MechTypes, \
4545
ASN1_SUPPORTED_MECH
46+
from impacket.examples.utils import get_address
4647

4748

4849
class WCFRelayServer(Thread):
4950
class WCFServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
5051
def __init__(self, server_address, request_handler_class, config):
5152
self.config = config
5253
self.daemon_threads = True
53-
if self.config.ipv6:
54-
self.address_family = socket.AF_INET6
54+
self.address_family, server_address = get_address(server_address[0], server_address[1], self.config.ipv6)
5555
self.wpad_counters = {}
5656
socketserver.TCPServer.__init__(self, server_address, request_handler_class)
5757

impacket/examples/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,9 @@ def parse_identity(credentials, hashes=None, no_pass=False, aesKey=None, k=False
322322

323323
def get_address(ip, port, ipv6=False):
324324
address = (ip, port)
325+
address_family = socket.AF_INET
325326
if ipv6:
327+
address_family = socket.AF_INET6
326328
# scope_id (after %) can be present or not - if not, default: 0
327329
ip_parts = ip.split('%')
328330
scope_id = ip_parts[1] if len(ip_parts) == 2 else 0
@@ -333,11 +335,11 @@ def get_address(ip, port, ipv6=False):
333335
except ValueError:
334336
scope_id = socket.if_nametoindex(scope_id)
335337
address = address + (0, scope_id)
336-
return address
338+
return address_family, address
337339

338340
import socket
339341
def get_connected_socket(ip, port, ipv6=False):
340342
s = socket.socket(socket.AF_INET6 if ipv6 else socket.AF_INET)
341-
address = get_address(ip, port, ipv6)
343+
_, address = get_address(ip, port, ipv6)
342344
s.connect(address)
343345
return s

impacket/smbserver.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3989,7 +3989,22 @@ def finish(self):
39893989

39903990
class SMBSERVER(socketserver.ThreadingMixIn, socketserver.TCPServer):
39913991
# class SMBSERVER(socketserver.ForkingMixIn, socketserver.TCPServer):
3992-
def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser=None):
3992+
def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser=None, ipv6=False):
3993+
# duplicate of https://github.com/fortra/impacket/blob/082dca34a376d13c70b0df6a1d9048ce98fe9498/impacket/examples/utils.py#L323
3994+
# didn't reuse that same function in order not to make a class from the library depend on one from impacket/examples
3995+
if ipv6:
3996+
self.address_family = socket.AF_INET6
3997+
# scope_id (after %) can be present or not - if not, default: 0
3998+
ip_parts = server_address[0].split('%')
3999+
scope_id = ip_parts[1] if len(ip_parts) == 2 else 0
4000+
# convert scope_id to int (expected by s.connect)
4001+
# if exception, assume the interface name and convert to index
4002+
try:
4003+
scope_id = int(scope_id)
4004+
except ValueError:
4005+
scope_id = socket.if_nametoindex(scope_id)
4006+
server_address = server_address + (0, scope_id)
4007+
39934008
socketserver.TCPServer.allow_reuse_address = True
39944009
socketserver.TCPServer.__init__(self, server_address, handler_class)
39954010

@@ -4880,10 +4895,9 @@ class SimpleSMBServer:
48804895
:param string configFile: a file with all the servers' configuration. If no file specified, this class will create the basic parameters needed to run. You will need to add your shares manually tho. See addShare() method
48814896
"""
48824897

4883-
def __init__(self, listenAddress='0.0.0.0', listenPort=445, configFile='', smbserverclass=SMBSERVER):
4898+
def __init__(self, listenAddress='0.0.0.0', listenPort=445, configFile='', smbserverclass=SMBSERVER, ipv6=False):
48844899
if configFile != '':
4885-
#self.__server = SMBSERVER((listenAddress, listenPort))
4886-
self.__server = smbserverclass((listenAddress, listenPort))
4900+
self.__server = smbserverclass((listenAddress, listenPort), ipv6=ipv6)
48874901
self.__server.processConfigFile(configFile)
48884902
self.__smbConfig = None
48894903
else:
@@ -4908,7 +4922,7 @@ def __init__(self, listenAddress='0.0.0.0', listenPort=445, configFile='', smbse
49084922
self.__smbConfig.set('IPC$', 'read only', 'yes')
49094923
self.__smbConfig.set('IPC$', 'share type', '3')
49104924
self.__smbConfig.set('IPC$', 'path', '')
4911-
self.__server = smbserverclass((listenAddress, listenPort), config_parser=self.__smbConfig)
4925+
self.__server = smbserverclass((listenAddress, listenPort), config_parser=self.__smbConfig, ipv6=ipv6)
49124926
self.__server.processConfigFile()
49134927

49144928
# Now we have to register the MS-SRVS server. This specially important for

0 commit comments

Comments
 (0)