
Botnet command & control monitor
Hale ist ein Botnet-Command-&-Control-Monitor/Spion mit modularem Design, der es einfach macht, neue Module zu entwickeln, die neue Protokolle von C&C-Servern überwachen. Hale wird mit IRC- und HTTP-Monitoren ausgeliefert, die mit Twisted entwickelt wurden, um die Skalierbarkeit einer großen Anzahl von Verbindungen zu bewältigen. Diese Module haben konfigurierbare Protokollgrammatiken und Bot-Einstellungen, können aber auch an Ihre Bedürfnisse angepasst werden. Alle erfassten Logs und Dateien werden in einer Datenbank gespeichert, bei IRC zusätzlich auch die verfolgten IP-Nummern.
Um den Standort des Betreibers zu verbergen, können Verbindungen über SOCKSv5-Proxys hergestellt werden. Dies ist über die Weboberfläche konfigurierbar, auf der auch alle Logs zum Durchsuchen sowie statistische Diagramme und Zeitleisten verfügbar sind. Die Oberfläche wurde mit Django und der Google Visualization API entwickelt. Zusätzliche Funktionen der Weboberfläche sind eine RESTful-API mit OAuth-Unterstützung und eine Suchmaschine.
Die Hauptidee von Hale ist es, die Jagd auf Botnetze und die Forschung zu unterstützen, indem ein Netzwerk von Sensoren (Hale-Monitore) aufgebaut wird. Um diese Idee zu verbessern, steht ein XMPP-Bot zur Verfügung, der sich mit einem zentralen XMPP-Server verbindet, auf dem derzeit zwei verschiedene Gruppenräume genutzt werden: einer zur Koordinierung zwischen den Sensoren und einer zum Teilen von Logs und Dateien. Der Koordinierungsraum verwendet Botnet-Hashes, die aus den eindeutigen Schlüsseln in den Botnet-Einstellungen gebildet werden, sodass zwei Botnetze mit demselben Hash (Identität) nicht gleichzeitig überwacht werden müssen – dies verbessert die Auslastung. Damit Dritte dieses Netzwerk nutzen können, kann ein Bot dem Koordinierungsraum beitreten und einen Sensor bitten, ein Botnet zu verfolgen, wenn es noch nicht verfolgt wird, indem die entsprechenden Konfigurationen gesendet werden. Darüber hinaus können Dritt-Bots im Share-Raum in Echtzeit auf von den Sensoren erfasste Logs und Dateien zugreifen. Zur Unterstützung der Log-Historie kann die Web-API verwendet werden, die GET-Anfragen unterstützt.
Hale hat folgende Abhängigkeiten:
Python == 2.6
Django == 1.2.1
Twisted == 10.1.0
GeoIP-Python == 1.2.4 (sowie GeoIP C-Bibliothek)
Whoosh == 0.3.18
django-haystack == 1.0.1-final
django-piston == 0.2.3rc1
pefile == 1.2.10-63
sleekxmpp == 0.9Rrc1
wsgiref == 0.1.2
zope.interface == 3.6.1
oauth2 == 1.2.0
httplib2 == 0.6.0
Zusätzlich benötigt der Monitor einen Datenbank-Backend-Treiber, der der von Django verwendeten Datenbank entspricht. Wenn diese Bibliotheken installiert sind, laden Sie den Quellcode von hier herunter und entpacken Sie ihn an einem beliebigen Ort.
Erstellen Sie zunächst eine Datenbank, die von Hale verwendet wird. Die Datenbank-Engine kann frei gewählt werden. Wenn Sie eine vorhandene Datenbank verwenden, überspringen Sie diesen Schritt.
Im nächsten Schritt installieren Sie die Python-Datenbank-Backend-Treiber, die der verwendeten Server-Engine entsprechen.
Bearbeiten Sie settings.py in hale/src/webdb/ und ändern Sie die folgenden Konfigurationen: ENGINE, NAME, USER, PASSWORD, HOST und PORT. Die ENGINE-Einstellung ist z. B. django.db.backends.mysql, wenn Ihre Server-Engine MySQL ist. Die NAME-Einstellung ist der Name Ihrer Datenbank, den Sie beim Erstellen verwendet haben.
Wenn Sie nicht Ihre eigene Weboberfläche starten möchten, überspringen Sie diesen Schritt und gehen Sie zu 8). Ändern Sie in settings.py PATH_TO_APP, sodass er auf den vollständigen Pfad der Django-Anwendung zeigt, z. B. '/home/..../Hale/src/webdb'. Führen Sie im webdb-Verzeichnis folgenden Befehl aus: python manage.py syncdb. Wenn hier Fehler auftreten, sind die Datenbankeinstellungen in settings.py wahrscheinlich falsch. Legen Sie während der Synchronisation auch den Superuser fest, der für die Benutzerverwaltung verwendet wird.
Um die Suche in der Weboberfläche zu unterstützen, führen Sie python manage.py rebuild_index aus, damit die Suchmaschine zum ersten Mal indexiert. Dadurch wird ein Verzeichnis namens erstellt. Damit der Webserver dort schreiben kann, führen Sie aus. Danach führen Sie stattdessen aus und sollten dies als Cron-Job einrichten, um die Indizes in einem von Ihnen gewählten regelmäßigen Intervall zu aktualisieren.
Alias /media /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/
<Location /media>
Order allow,deny
Allow from all
</Location>
WSGIDaemonProcess username processes=2 maximum-requests=500 threads=10
WSGIProcessGroup group
WSGIScriptAlias / /home/..../webdb/django.wsgi
und bearbeiten Sie den Benutzernamen und die Gruppe, unter denen der WSGI-Daemon laufen soll. WSGIScriptAlias sollte auf den vollständigen Pfad zur Datei django.wsgi im Verzeichnis webdb gesetzt werden. Der oben angegebene Alias wird benötigt, damit die Verwaltungsseite korrekt dargestellt wird. Um Module über die Weboberfläche hochladen zu können, führen Sie chmod o+w webdb/modules aus.
Laden Sie Module aus hale/src/modules/ hoch oder schreiben Sie eigene (siehe Abschnitt Entwicklung). Laden Sie das gewünschte Modul in der Administratoroberfläche hoch und bearbeiten Sie z. B. den Modulnamen zu irc und den Dateinamen zu ircModule.py. Geben Sie die entsprechenden Konfigurationsregeln für das Modul im entsprechenden Abschnitt in hale/conf/modules.conf an und fügen Sie sie in das Textfeld ein. Fügen Sie außerdem den Abschnitt uniqueKeys für das hochgeladene Modul hinzu.
Bevor Sie den Monitor ausführen, bearbeiten Sie hale.conf in hale/src/conf/, falls Sie einen XMPP-Server verwenden möchten. Um den XMPP-Bot zu aktivieren, setzen Sie die Einstellung use auf True und bearbeiten Sie entweder die Anmeldeinformationen für ein vorhandenes Konto und einen Server oder starten Sie Ihren eigenen XMPP-Server. Ein wichtiger Schritt beim Starten eines XMPP-Servers ist es, die maximale Stanza-Größe vom Standardwert auf etwa 10 MB zu erhöhen. Andernfalls ist die Malware-Werbung nicht möglich. Die Kanaleinstellungen in hale.conf werden für den Share-Gruppenraum verwendet, der vom Bot genutzt wird, und die Koordinierungseinstellung wird für den Gruppenraum verwendet, in dem die gesamte Koordinierung zwischen den Sensoren stattfindet.
Bearbeiten Sie und legen Sie die Client- und Server-Einstellungen fest.
Um den Monitor zu starten, gehen Sie zu hale/src/ und führen Sie python server.py aus. Wenn er mit Fehlern startet, ist entweder die Django-Datei settings.py nicht korrekt eingerichtet oder es fehlen einige Bibliotheken. Mit dem Client ist es möglich, Befehle an den Server zu senden, aber der Benutzer muss sich gegenüber dem Server authentifizieren. Zugriff wird für Benutzer gewährt, die über die Weboberfläche als Mitarbeiter (staff members) eingestellt sind. Wenn der Client läuft, geben Sie help oder ? ein, um die verfügbaren Befehle anzuzeigen. Geben Sie help command ein, um weitere Informationen zu einem bestimmten Befehl zu erhalten. Um einen Monitor-Bot zu starten, bearbeiten Sie zunächst die Datei hale/src/conf/modules.conf, z. B. mit einer IRC-Konfiguration wie folgt:
[uniqueKeys]
irc = botnet, *grammar
[ircConf]
module = irc
botnet = irc.freenode.net
port = 6667
password = None
nick = nickname
username = agent007
realname = Spying
channel = #channelname
channel_pass = somepass
pass_grammar = PASS
nick_grammar = NICK
user_grammar = USER
join_grammar = JOIN
version_grammar = VERSION
time_grammar = TIME
privmsg_grammar = PRIVMSG
topic_grammar = TOPIC
currenttopic_grammar = 332
ping_grammar = PING
pong_grammar = PONG
Bearbeiten oder erstellen Sie eine neue Konfiguration, indem Sie einen neuen eindeutig benannten Abschnitt angeben (Teil [ircConf]). Oben in der Konfigurationsdatei gibt es einen Abschnitt namens uniqueKeys, in dem alle eindeutigen Felder für ein Modul angegeben werden und der zur Erzeugung des Botnet-Hashs verwendet wird. Dies sollte normalerweise nicht geändert werden, um eine korrekte Botnet-Verfolgung zu gewährleisten. Wenn dies erledigt ist, führen Sie useconf section aus, um die Konfiguration zu laden, und starten Sie dann den Bot mit exec modulename id, wobei id von Ihnen festgelegt wird, um das Botnet zu identifizieren.
Die Weboberfläche bietet Zugriff auf alle erfassten Daten in der Datenbank, die über die Indexseite zugänglich sind. Es gibt auch eine Suchfunktion, die es dem Benutzer ermöglicht, nach Botnet- und Datei-Hashes, zugehörigen IP-Nummern, Botnet-IDs, verwendeten Botnet-Modulen und Botnet-Hosts zu suchen. Wenn der Benutzer Zugriff zum Bearbeiten von Proxys oder Modulen hat, kann dies im Admin-Bereich erfolgen, die URL dazu ist http://.../admin. Der Administrator kann Benutzermodi festlegen und auch Verbraucher (Consumers) für die Web-API hinzufügen.
Implementieren Sie das Modul, zum Beispiel:
import moduleManager from utils import moduleInterface
@moduleManager.register("irc") def module_setup(config, hash): """ Function to register modules, simply implement this to pass along the config and hash to the module object and return the it back. """
return IRC(config, hash)
class IRC(moduleInterface.Module):
def __init__(self, config, hash):
self.config = config
self.hash = hash
# must be implemented
def stop(self):
# stop execution
# must be implemented
def run(self):
# start execution
# must be implemented
def getConfig(self):
return self.config
Fügen Sie einen Decorator für die Registerfunktion (in diesem Fall module_setup) hinzu, die mit der aktuellen Konfiguration als Argument und dem aus den eindeutigen Schlüsseln erstellten Konfigurations-Hash aufgerufen wird. Diese Funktion kann beliebig benannt werden. Übergeben Sie die Konfigurationen an das Modulobjekt. Der Config-Handler fängt KeyErrors ab. Wenn also falsche Konfigurationen an diese Funktion gesendet werden, wird der Config-Handler Sie darüber informieren.
Befolgen Sie auch die Namenskonvention nameModule.py und @moduleManager.register("name") und importieren Sie moduleManager, andernfalls informiert Sie der ModuleManager über Fehler.
Der Rest des Modulcodes wird hier nicht gezeigt, sollte aber ein Twisted-Factory-Objekt erstellen und dieses in der run-Methode mit dem Reaktor starten. Siehe die vorhandenen Module als Beispiel. Tutorials zur Programmierung mit Twisted finden Sie hier. Es gibt auch einige Hilfsfunktionen (utils), die bei der Entwicklung von Modulen verwendet werden können. Dies geschieht wie folgt:
Socksify:
# import all utils
from utils import *
# in the constructor create a new proxy object
self.prox = proxySelector.ProxySelector()
# in the run method add the following after having created the factory method.
proxyInfo = self.prox.getRandomProxy()
if proxyInfo == None:
self.connector = reactor.connectTCP(host, port, factory)
else:
proxyHost = proxyInfo['HOST']
proxyPort = proxyInfo['PORT']
proxyUser = proxyInfo['USER']
proxyPass = proxyInfo['PASS']
socksify = socks5.ProxyClientCreator(reactor, factory)
if len(proxyUser) == 0:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE")
else:
self.connector = socksify.connectSocks5Proxy(host, port, proxyHost, proxyPort, "HALE", proxyUser, proxyPass)
Fehlerbehandlung bei Verbindungen im Factory-Objekt:
def clientConnectionFailed(self, connector, reason):
"""
Called on failed connection to server
"""
moduleCoordinator.ModuleCoordinator().putError("Error connecting to " + self.config['botnet'], self.module)
def clientConnectionLost(self, connector, reason):
"""
Called on lost connection to server
"""
moduleCoordinator.ModuleCoordinator().putError("Connection lost to " + self.config['botnet'], self.module)
Dadurch werden die Fehler an den Fehler-Eimer gesendet, der durch Eingabe von showlog in der CLI zugänglich ist.
Protokollierung (Logging):
# in the factory create the following method to handle logs (note that the hash and config must be sent to the factory)
# and call it in the protocol class with: self.factory.putLog(data)
def putLog(self, log):
"""
Put log to the event handler
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.LOG_EVENT, log, self.hash, self.config)
# apply reg expression to look for URLs containing possible malware
# and call it in the protocol class with: self.factory.checkForURL(data)
def checkForURL(self, data):
"""
Check for URL in the event handler
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.URL_EVENT, data, self.hash)
# if you module should detect IP numbers of other bots and herders implement the following method in the factory
def addRelIP(self, data):
"""
Put possible ip related to the botnet being monitored
in the event handler.
"""
moduleCoordinator.ModuleCoordinator().addEvent(moduleCoordinator.RELIP_EVENT, data, self.hash)
Die Verarbeitung zugehöriger IPs erfolgt durch Anwendung eines regulären Ausdrucks, der für das vom Modul zu unterstützende Protokoll verwendet wird. Im Fall des IRC-Moduls sieht der Code so aus:
checkHost = data.split(':')[1].split(' ')[0].strip()
match = self.factory.expr.findall(checkHost)
if match:
self.factory.addRelIP(data.split('@')[1].split(' ')[0].strip())
wobei der reguläre Ausdruck wie folgt ist:
self.expr = re.compile('!~.*?@')
2) Ziehen Sie die Datei in das modules-Verzeichnis. Der ModuleManager importiert sie dann automatisch und prüft auf Fehler.
Bearbeiten Sie in modules.conf die Konfiguration
Laden Sie das Modul über die Weboberfläche hoch, indem Sie den Modulnamen auf z. B. irc, den Dateinamen auf ircModule.py setzen und dann ein Konfigurationsbeispiel für dieses Modul hinzufügen.
Wenn eine Anfrage für ein zu verfolgendes Botnet gesendet wird, erfolgt die Anfrage wie folgt im Gruppenchat-Koordinierungsraum:
sensorLoadReq
worauf alle Sensoren mit ihrer ID und Warteschlangenlänge (Anzahl der überwachten Botnetze) antworten:
sensorLoadAck id=353f6650859547ed06597dbfa1dcfd88 queue=0
Der Feeder wählt dann einen Sensor basierend auf diesen Informationen aus, z. B. die niedrigste Warteschlangenlänge. Wenn diese für mehrere Sensoren gleich ist, wird der Sensor mit der alphabetisch niedrigsten ID ausgewählt.
Wenn der Feeder einen Sensor ausgewählt hat, sendet er eine private Chat-Nachricht an den Sensor:
startTrackReq config
wobei config eine Zeichenfolgendarstellung der Konfiguration ist, z. B.
module=irc botnet=irc.freenode.net etc..
Der Sensor antwortet dann mit einer Bestätigung zusammen mit dem Konfigurations-Hash, der verwendet werden kann, um die Botnet-Protokolle von anderen Protokollen im Share-Kanal zu unterscheiden. Beispiel einer Bestätigung:
startTrackAck hash
falls niemand anderes dieses Botnet bereits überwacht. Andernfalls wird ein startTrackNack empfangen, wenn das Botnet bereits überwacht wird oder der Sensor das für dieses Botnet erforderliche Modul nicht installiert hat. Das Teilen von Malware erfolgt, indem Sensoren eine Nachricht wie folgt senden:
fileCaptured hash=353f6650... file content
wobei der Inhalt Base64-codiert ist und direkt nach dem Datei-Hash-Wert steht.
Um Zugriff auf die API zu erhalten, benötigen Sie einen Consumer-Key und einen Secret-Key, die vom Administrator erstellt werden können und mit OAuth zur Authentifizierung verwendet werden. Die folgenden URLs stehen zur Verfügung, um Daten im JSON-Format abzurufen:
http://.../api/botnet antwortet mit allen überwachten Botnetzen
http://.../api/botnet/botnethash antwortet mit dem Botnet, dessen Hash gleich botnethash ist
http://.../api/host/hostname antwortet mit allen überwachten Botnetzen, deren Host gleich hostname ist
http://.../api/type/module antwortet mit allen überwachten Botnetzen, die das Modul verwenden
http://.../api/botips/hash antwortet mit allen von dem Botnet mit dem Wert hash erfassten IPs
http://.../api/bologs/hash antwortet mit allen Protokollen für das Botnet mit dem Wert hash
http://.../api/bofiles/hash antwortet mit den Datei-Hashes, die von dem Botnet mit dem Wert hash erfasst wurden
http://.../api/file/hash gibt Botnet-Informationen für diejenigen zurück, die die Datei mit dem angegebenen Hash erfasst haben
http://.../api/ip/addr antwortet mit Botnet-Informationen für diejenigen, die eine IP mit der Nummer addr erkannt haben
Beachten Sie, dass derzeit nur GET-Anfragen möglich sind.
whoosh.index/chmod o+w whoosh.index/python manage.py update_indexFühren Sie python manage.py runserver aus und gehen Sie zu http://127.0.0.1:8000, um zu überprüfen, ob die Einrichtung korrekt war.
Der Befehl runserver startet einen Entwicklungsserver, der aufgrund von Leistungsproblemen nicht für den Produktionseinsatz empfohlen wird. Stattdessen setzen Sie die Weboberfläche ein, indem Sie mod_wsgi für Apache installieren. Angenommen, Sie verwenden Ubuntu, führen Sie apt-get install libapache2-mod-wsgi aus. Fügen Sie in /etc/apache2/sites-available/default Folgendes hinzu:
hale.conf