- Whole framework now requires root privs

- Added an internal DNS server
- Proxy can now use our custom DNS server (DNSChef) or Twisted's
- Removed priv check from plugins
- DNS spoofing fully re-written
- Iptables rules are now checked and set between plugins
This commit is contained in:
byt3bl33d3r 2015-04-12 01:49:43 +02:00
parent c8732d60eb
commit 9a1c3b0ec4
22 changed files with 129 additions and 90 deletions

View file

@ -8,7 +8,6 @@
#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
@ -23,28 +22,22 @@
rpcip = 127.0.0.1
rpcpass = abc123
#
#Plugin configuration starts here
#
[Spoof]
[[DHCP]]
ip_pool = 192.168.2.10-50
subnet = 255.255.255.0
dns_server = 192.168.2.20 #optional
[[DNS]]
#
#Here you can configure DNSChef's options
#Here you can configure MITMf's internal DNS server
#
port = 53 #Port to listen on
nameservers = 8.8.8.8 #Supported formats are 8.8.8.8#53 or 4.2.2.1#53#tcp or 2001:4860:4860::8888
tcp = Off #Use the TCP DNS proxy instead of the default UDP
ipv6 = Off #Run in IPv6 mode
resolver = dnschef #Can be set to 'twisted' or 'dnschef' ('dnschef' is highly reccomended)
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
#
nameservers = 8.8.8.8
[[[A]]] # Queries for IPv4 address records
*.thesprawl.org=192.0.2.1
@ -82,6 +75,17 @@
[[[RRSIG]]] #FORMAT: covered algorithm labels labels orig_ttl sig_exp sig_inc key_tag name base64(sig)
*.thesprawl.org=A 5 3 86400 20030322173103 20030220173103 2642 thesprawl.org. oJB1W6WNGv+ldvQ3WDG0MQkg5IEhjRip8WTrPYGv07h108dUKGMeDPKijVCHX3DDKdfb+v6oB9wfuh3DTJXUAfI/M0zmO/zz8bW0Rznl8O3tGNazPwQKkRN20XPXV6nwwfoXmJQbsLNrLfkGJ5D6fwFm8nN+6pBzeDQfsS3Ap3o=
#
#Plugin configuration starts here
#
[Spoof]
[[DHCP]]
ip_pool = 192.168.2.10-50
subnet = 255.255.255.0
dns_server = 192.168.2.20 #optional
[Responder]
#Set these values to On or Off, so you can control which rogue authentication server is turned on.

View file

@ -16,7 +16,7 @@
# USA
#
import urlparse, logging, os, sys, random, re
import urlparse, logging, os, sys, random, re, dns.resolver
from twisted.web.http import Request
from twisted.web.http import HTTPChannel
@ -43,8 +43,8 @@ class ClientRequest(Request):
the magic begins. Here we remove the client headers we dont like, and then
respond with either favicon spoofing, session denial, or proxy through HTTP
or SSL to the server.
'''
'''
def __init__(self, channel, queued, reactor=reactor):
Request.__init__(self, channel, queued)
self.reactor = reactor
@ -54,6 +54,12 @@ class ClientRequest(Request):
self.dnsCache = DnsCache.getInstance()
self.plugins = ProxyPlugins.getInstance()
#self.uniqueId = random.randint(0, 10000)
#Use are own DNS server instead of reactor.resolve()
self.resolver = URLMonitor.getInstance().getResolver()
self.customResolver = dns.resolver.Resolver()
self.customResolver.nameservers = ['127.0.0.1']
self.customResolver.port = URLMonitor.getInstance().getResolverPort()
def cleanHeaders(self):
headers = self.getAllHeaders().copy()
@ -173,7 +179,7 @@ class ClientRequest(Request):
self.proxyViaHTTP(address, self.method, path, postData, headers, port)
def handleHostResolvedError(self, error):
logging.warning("[ClientRequest] Host resolution error: " + str(error))
logging.debug("[ClientRequest] Host resolution error: " + str(error))
try:
self.finish()
except:
@ -186,8 +192,18 @@ class ClientRequest(Request):
mitmf_logger.debug("[ClientRequest] Host cached: %s %s" % (host, str(address)))
return defer.succeed(address)
else:
mitmf_logger.debug("[ClientRequest] Host not cached.")
return reactor.resolve(host)
if self.resolver == 'dnschef':
try:
address = str(self.customResolver.query(host)[0].address)
return defer.succeed(address)
except Exception:
return defer.fail()
elif self.resolver == 'twisted':
return reactor.resolve(host)
def process(self):
mitmf_logger.debug("[ClientRequest] Resolving host: %s" % (self.getHeader('host')))

View file

@ -47,6 +47,8 @@ class URLMonitor:
self.hsts = False
self.app = False
self.hsts_config = None
self.resolver = 'dnschef'
self.resolverport = 53
@staticmethod
def getInstance():
@ -54,6 +56,22 @@ class URLMonitor:
URLMonitor._instance = URLMonitor()
return URLMonitor._instance
#This is here because I'm lazy
def setResolver(self, resolver):
self.resolver = str(resolver).lower()
#This is here because I'm lazy
def getResolver(self):
return self.resolver
#This is here because I'm lazy
def setResolverPort(self, port):
self.resolverport = int(port)
#This is here because I'm lazy
def getResolverPort(self):
return self.resolverport
def isSecureLink(self, client, url):
for expression in URLMonitor.javascriptTrickery:
@ -133,13 +151,12 @@ class URLMonitor:
self.faviconSpoofing = faviconSpoofing
def setHstsBypass(self, hstsconfig):
if hstsconfig:
self.hsts = True
self.hsts_config = hstsconfig
self.hsts = True
self.hsts_config = hstsconfig
for k,v in self.hsts_config.iteritems():
self.sustitucion[k] = v
self.real[v] = k
for k,v in self.hsts_config.iteritems():
self.sustitucion[k] = v
self.real[v] = k
def setAppCachePoisoning(self):
self.app = True

View file

@ -30,19 +30,33 @@ class SystemConfig:
file.write(str(value))
file.close()
class iptables:
class IpTables:
@staticmethod
def Flush():
os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X')
_instance = None
@staticmethod
def HTTP(http_redir_port):
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % http_redir_port)
def __init__(self):
self.dns = False
self.http = False
@staticmethod
def DNS(ip, port):
os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to %s:%s' % (ip, port))
@staticmethod
def getInstance():
if IpTables._instance == None:
IpTables._instance = IpTables()
return IpTables._instance
def Flush(self):
os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X')
self.dns = False
self.http = False
def HTTP(self, http_redir_port):
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % http_redir_port)
self.http = True
def DNS(self, ip, port):
os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to %s:%s' % (ip, port))
self.dns = True
class Banners:

@ -1 +1 @@
Subproject commit fbc5ec324b6045db2f6cc62662ab51d3ff979ec8
Subproject commit 9707672de62bd42f651fabc6f9d368d7a67b4d99

View file

@ -36,14 +36,6 @@ from scapy.all import get_if_addr, get_if_hwaddr
from plugins import *
plugin_classes = plugin.Plugin.__subclasses__()
try:
import netfilterqueue
if netfilterqueue.VERSION[1] is not 6:
print "[-] Wrong version of NetfilterQueue library installed!"
print "[-] Download it from here https://github.com/fqrouter/python-netfilterqueue and manually install it!"
except ImportError:
print "[-] NetfilterQueue library missing! DNS tampering will not work"
try:
import user_agents
except ImportError:
@ -52,9 +44,13 @@ except ImportError:
mitmf_version = "0.9.6"
sslstrip_version = "0.9"
sergio_version = "0.2.1"
dnschef_version = "0.4"
Banners().printBanner()
if os.geteuid() != 0:
sys.exit("[-] When man-in-the-middle you want, run as r00t you will, hmm?")
parser = argparse.ArgumentParser(description="MITMf v%s - Framework for MITM attacks" % mitmf_version, version=mitmf_version, usage='', epilog="Use wisely, young Padawan.",fromfile_prefix_chars='@')
#add MITMf options
mgroup = parser.add_argument_group("MITMf", "Options for MITMf")
@ -114,15 +110,6 @@ if config_args:
sys.argv.append(arg)
args = parser.parse_args()
#Check to see if called plugins require elevated privs
try:
for p in plugins:
if (vars(args)[p.optname] is True) and (p.req_root is True):
if os.geteuid() != 0:
sys.exit("[-] %s plugin requires root privileges" % p.name)
except AttributeError:
sys.exit("[-] %s plugin is missing the req_root attribute" % p.name)
####################################################################################################
# Here we check for some variables that are very commonly used, and pass them down to the plugins
@ -189,8 +176,18 @@ else:
from core.sslstrip.StrippingProxy import StrippingProxy
from core.sslstrip.URLMonitor import URLMonitor
from libs.dnschef.dnschef import DNSChef
URLMonitor.getInstance().setFaviconSpoofing(args.favicon)
URLMonitor.getInstance().setResolver(args.configfile['MITMf']['DNS']['resolver'])
URLMonitor.getInstance().setResolverPort(args.configfile['MITMf']['DNS']['port'])
DNSChef.getInstance().setCoreVars(args.configfile['MITMf']['DNS'])
if args.configfile['MITMf']['DNS']['tcp'].lower() == 'on':
DNSChef.getInstance().startTCP()
else:
DNSChef.getInstance().startUDP()
CookieCleaner.getInstance().setEnabled(args.killsessions)
ProxyPlugins.getInstance().setPlugins(load)
@ -207,7 +204,8 @@ else:
print "|"
print "|_ Sergio-Proxy v%s online" % sergio_version
print "|_ SSLstrip v%s by Moxie Marlinspike running...\n" % sslstrip_version
print "|_ SSLstrip v%s by Moxie Marlinspike online" % sslstrip_version
print "|_ DNSChef v%s online\n" % dnschef_version
reactor.run()

View file

@ -39,7 +39,6 @@ class AppCachePlugin(Plugin):
implements = ["handleResponse"]
version = "0.3"
has_opts = False
req_root = False
def initialize(self, options):
self.options = options

View file

@ -40,7 +40,6 @@ class BeefAutorun(Inject, Plugin):
tree_output = []
depends = ["Inject"]
version = "0.3"
req_root = False
has_opts = False
def initialize(self, options):

View file

@ -33,7 +33,6 @@ class BrowserProfiler(Inject, Plugin):
depends = ["Inject"]
version = "0.2"
has_opts = False
req_root = False
def initialize(self, options):
Inject.initialize(self, options)

View file

@ -29,7 +29,6 @@ class CacheKill(Plugin):
bad_headers = ['if-none-match', 'if-modified-since']
version = "0.1"
has_opts = True
req_root = False
def add_options(self, options):
options.add_argument("--preserve-cookies", action="store_true", help="Preserve cookies (will allow caching in some situations).")

View file

@ -81,7 +81,6 @@ class FilePwn(Plugin):
tree_output = ["BDFProxy v0.2 online"]
version = "0.2"
has_opts = False
req_root = False
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''

View file

@ -35,7 +35,6 @@ class Inject(CacheKill, Plugin):
optname = "inject"
implements = ["handleResponse", "handleHeader", "connectionMade"]
has_opts = True
req_root = False
desc = "Inject arbitrary content into HTML content"
version = "0.2"
depends = ["CacheKill"]

View file

@ -30,7 +30,6 @@ class jskeylogger(Inject, Plugin):
depends = ["Inject"]
version = "0.2"
has_opts = False
req_root = False
def initialize(self, options):
Inject.initialize(self, options)

View file

@ -39,7 +39,6 @@ class Replace(CacheKill, Plugin):
depends = ["CacheKill"]
version = "0.1"
has_opts = True
req_root = False
def initialize(self, options):
self.options = options

View file

@ -34,7 +34,6 @@ class Responder(Plugin):
tree_output = ["NBT-NS, LLMNR & MDNS Responder v2.1.2 by Laurent Gaffie online"]
version = "0.2"
has_opts = True
req_root = True
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''

View file

@ -30,7 +30,6 @@ class SMBAuth(Inject, Plugin):
depends = ["Inject"]
version = "0.1"
has_opts = True
req_root = False
def initialize(self, options):
Inject.initialize(self, options)

View file

@ -19,22 +19,20 @@
#
import sys
import dns.resolver
import logging
from plugins.plugin import Plugin
from core.utils import SystemConfig
from core.utils import IpTables
from core.sslstrip.URLMonitor import URLMonitor
from libs.dnschef.dnschef import start_dnschef
from libs.dnschef.dnschef import DNSChef
class HSTSbypass(Plugin):
name = 'SSLstrip+'
optname = 'hsts'
desc = 'Enables SSLstrip+ for partial HSTS bypass'
version = "0.4"
tree_output = ["SSLstrip+ by Leonardo Nve running", "DNSChef v0.3 online"]
tree_output = ["SSLstrip+ by Leonardo Nve running"]
has_opts = False
req_root = True
def initialize(self, options):
self.options = options
@ -42,10 +40,17 @@ class HSTSbypass(Plugin):
try:
hstsconfig = options.configfile['SSLstrip+']
dnsconfig = options.configfile['Spoof']['DNS']
except Exception, e:
sys.exit("[-] Error parsing config for SSLstrip+: " + str(e))
URLMonitor.getInstance().setHstsBypass(hstsconfig)
if not options.manualiptables:
if IpTables.getInstance().dns is False:
IpTables.getInstance().DNS(options.ip_address, options.configfile['MITMf']['DNS']['port'])
start_dnschef(options, dnsconfig, hstsconfig)
URLMonitor.getInstance().setHstsBypass(hstsconfig)
DNSChef.getInstance().setHstsBypass(hstsconfig)
def finish(self):
if not self.manualiptables:
if IpTables.getInstance().dns is True:
IpTables.getInstance().Flush()

View file

@ -41,7 +41,6 @@ class SessionHijacker(Plugin):
implements = ["cleanHeaders"] #["handleHeader"]
version = "0.1"
has_opts = True
req_root = False
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''

View file

@ -45,7 +45,6 @@ class Sniffer(Plugin):
implements = ["sendRequest"]
version = "0.1"
has_opts = False
req_root = True
def initialize(self, options):
self.options = options

View file

@ -21,11 +21,11 @@
import logging
import sys
from core.utils import SystemConfig
from core.utils import SystemConfig, IpTables
from core.sslstrip.DnsCache import DnsCache
from core.wrappers.protocols import _ARP, _DHCP, _ICMP
from plugins.plugin import Plugin
from libs.dnschef.dnschef import start_dnschef
from libs.dnschef.dnschef import DNSChef
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import *
@ -35,14 +35,12 @@ class Spoof(Plugin):
optname = "spoof"
desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS"
version = "0.6"
tree_output = []
has_opts = True
req_root = True
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.dnscfg = options.configfile['Spoof']['DNS']
self.dnscfg = options.configfile['MITMf']['DNS']
self.dhcpcfg = options.configfile['Spoof']['DHCP']
self.target = options.target
self.manualiptables = options.manualiptables
@ -91,10 +89,10 @@ class Spoof(Plugin):
if options.dns:
if not options.manualiptables:
SystemConfig.iptables.DNS(options.ip_address, self.dnscfg['port'])
if IpTables.getInstance().dns is False:
IpTables.getInstance().DNS(options.ip_address, self.dnscfg['port'])
self.tree_output.append("DNSChef v0.3 online")
start_dnschef(options, self.dnscfg)
DNSChef.getInstance().loadRecords(self.dnscfg)
if not options.arp and not options.icmp and not options.dhcp and not options.dns:
sys.exit("[-] Spoof plugin requires --arp, --icmp, --dhcp or --dns")
@ -102,7 +100,8 @@ class Spoof(Plugin):
SystemConfig.setIpForwarding(1)
if not options.manualiptables:
SystemConfig.iptables.HTTP(options.listen)
if IpTables.getInstance().http is False:
IpTables.getInstance().HTTP(options.listen)
for protocol in self.protocolInstances:
protocol.start()
@ -124,6 +123,6 @@ class Spoof(Plugin):
protocol.stop()
if not self.manualiptables:
SystemConfig.iptables.Flush()
IpTables.getInstance().Flush()
SystemConfig.setIpForwarding(0)

View file

@ -32,7 +32,6 @@ class Upsidedownternet(Plugin):
implements = ["handleResponse", "handleHeader"]
version = "0.1"
has_opts = False
req_root = False
def initialize(self, options):
from PIL import Image, ImageFile

View file

@ -10,7 +10,6 @@ class Plugin(object):
desc = ""
implements = []
has_opts = False
req_root = False
def __init__(self):
'''Called on plugin instantiation. Probably don't need this'''