DNS-based Intrusion Detection
Häufig lädt Malware Schadcode nach, oder ein Bot nimmt Kontakt mit einem C&C-Server auf. Die Kommunikationsmöglichkeiten sind dabei vielfältig, beispielsweise mittels IRC, P2P, XMPP oder auch einfach nur per HTTP-Download. Insbesondere im letzten Fall sucht die Malware Code oder Instruktionen unter einer URL, dessen Host-Anteil zunächst via DNS aufgelöst wird. An einem DNS-Resolver-Server kann nun nach dem Lookup eines verdächtigen DNS-Namens gesucht werden, was dann auf eine Infektion des anfragenden Clients hinweist.
Dieses klingt erstmal leicht, leider macht es einem die Malware teilweise schwieriger:
- nicht nur ein Hostname, sondern eine ganze Liste
- Verwendung eines Hosters, der auch viele andere Webseiten unter dem Hostname hostet, z.B. persönliche Homepages unter einer festen Domain
- errechnete Hostnamen, abhängig z.B. vom Datum oder dem aktuellen Inhalt eines Tweets sowie einem unbekannten Algorithmus
- indirekt, d.h. abrufen einer URL von einer festen, unverdächtigen Webseite (z.B. Twitter)
Und auch das eigene IT-Setup macht einem manchmal Schwierigkeiten:
- Natting,
- Active-Directory-Setups, bei denen der Domain-Controller direkt als DNS-Resolver der Clients verwendet wird.
Trotzdem gibt es genug Malware, für die die DNS-basierende Detection gut funktioniert, z.B. Conficker. Allerdings bietet sich wegen der großen Anzahl möglicher Domains eine kleine Datenbank an, Conficker-C generiert z.B. 50.000 Domain-Namen (aus denen eine Infektion aber nur einen deutlich kleineren Teil probiert). Einerseits kann man die DNS-Anfragen außerhalb des DNS-Servers an einem Span-Port mitlauschen, einfacher ist es aber durch Logging auf dem DNS-Server selbst.
Conficker
Conficker ist ein Beispiel von Malware, der in den meisten Varianten tagesabhängig generierte DNS-Namen für den Kontakt zu einem C&C-Server bzw. Upgrade/Payload benutzt. Die ersten Varianten A und B errechneten 250 DNS-Namen pro Tag. Nachdem der Algorithmus für die Berechnung durch Reverse-Engineering bekannt wurde, hatte die Conficker-Working-Group dabei eine Chance, möglichst viele dieser Namen zu reservieren, was den Betrieb eines C&C-Servers verhinderte und andererseits infizierte Clients detektieren konnte. Conficker-C generierte dann aber 50.000 DNS-Namen pro Tag.
Mehr zu Conficker, dem Reverse-Engineering und auch dem Vorausberechnungs-Tool für die DNS-Namen auf "Containing Conficker" von F. Leder und T. Werner. Wir haben die Namen für 2012 mit dem dort erhältlichen Downatool2 vorausberechnet: conficker-domains-2012.tar (2011: conficker-domains-2011.tar).
Conficker kann auch noch anders als über die DNS-Requests aufgefunden werden: durch Port-Scans (was auch nicht mehr alle Versionen verwenden) auf Port TCP-445 oder nach erfolgreichem DNS-Lookup durch HTTP-Zugriff auf die URL .../search?q=. Auf diesen beiden Mechanismen scheinen die DFN-Cert-Warnmeldungen zu Conficker-Bots zu basieren. Aber Windows-Portscans sind keine Seltenheit und zudem bei uns LUH-weit zwischen den Subnetzgrenzen gesperrt. Der HTTP-Zugriff erfolgt auch erst nach einem erfolgreichen DNS-Lookup - wir konnten aber beobachten, dass viele DNS-Lookups nicht aufgelöst werden können.
Seit ca. April 2009 haben wir auf unseren DNS-Resolvern kurzfristiges Request-Logging aktiviert und filtern diese Logs live auf Conficker-Zugriffe mittels eines Python-Skriptes (s.u.). Die Matches werden derzeit händisch bearbeitet, eine Automatisierung erfolgte bisher nicht, gingen wir doch zunächst nur von einem kurzen Überwachungszeitraum aus. Ein absolut sicheres Zeichen für den Befall eines Systemes sind mehrfache Lookups mit unterschiedlichen Conficker-Domains, diese Zugriffe erfolgen meist (aber nicht immer) in stündlich wiederkehrenden Salven. Es gibt auch zufällig gültige, harmlose Domains in den Conficker-Domains, die dann auch in den Logs auftauchen (gerne Requests durch unsere Mail-Server), was aufgrund der mangelnden Abwechslung aber sofort erkannt werden kann.
Nach Inbetriebnahme des Skriptes hatten wir ca. 3-5 Infektionen pro Tag im Netz, meist Studentenwohnheime oder WLAN, in den Instituten kaum und auch dort eher Gäste. Zwar wurde es über die letzten zwei Jahre deutlich weniger, der "Dienst" erfreut sich aber mit 3-4 Infektionen pro Woche leider noch immer zu großer Beliebtheit. In den zwei Jahren des Einsatzes hatten wir keinen einzigen False-Positive, nur die Identifikation des Clients war nicht immer leicht (Nat, AD).
Andere Malware
Neben Conficker haben wir auch andere DNS-Namen in unsere Überwachung aufgenommen. Einerseits für den Zeus-Bot die Liste vom ZeuS-Tracker. Zudem testweise alle C&C-Server der Malware-Domain-Liste auf malwaredomains.com (nicht alle Domains sind aussagekräftig, teils wegen Shared-Hosting, teils da der Domain-Lookup noch nicht auf eine erfolgreiche Infektion sondern nur auf den Abruf einer potentiell infektiösen Webseite hinweist).
Auch haben wir die Überwachung intern genutzt, um Zugriffe auf alte, nicht mehr aktive Update-Server zu monitoren, so dass wir gezielt veraltete Clients rausfinden konnten.
Einstellungen und Skripte
Bind-Logging
In der bei uns verwendeten Bind9-Version haben wir das Logging durch Eintragungen in die Datei named.conf.options aktiviert:
- Im Abschnitt logging mittels category queries { query_log; };
- und dann die Definition des Channels:
channel query_log {
file "/var/log/dns-logs/dns_query.log" versions 2 size 100m;
severity debug 1;
print-category yes;
print-severity no;
print-time yes;
};
Python-Filter-Skript
Das Skript entstand im April 2009 auf die Schnelle und sollte eigentlich nur kurz im Einsatz sein. Nun hat sich gezeigt, dass sich der längere und wohl sogar dauerhafte Einsatz lohnt. Nur das Skript ist noch nicht überarbeitet, es ist noch recht "händisch". Trotzdem geben wir es hier in der Hoffnung wieder, dass es auch anderen nützen oder als Ausgangpunkt dienen mag (Rückmeldungen, insbesondere über Einsatzerfahrungen sind willkommen).
Das Skript wird derzeit noch händisch mit nohup gestartet. Dabei hat es folgende Optionen (Ausgabe "dns-log-scan.py --help"):
Usage: dns-log-scan.py [options]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-f, --follow Warten auf weitere Eintraege in die Log-Datei oder
neue Log-Datei
-i FILE, --input=FILE
Einlesen der Log-Eintraege aus Datei statt von stdin
-o FILE, --output=FILE
Ausgabe der verdaechtigen Eintraege in Datei statt
stdout
-b FILE, --blacklist=FILE
Liste der zu meldenden DNS-Eintraege (Dateiname oder
Dateimaske)
Mit der Option "-i" wird die Bind-Log-Datei, bei uns also "-i /var/log/dns-logs/dns_query.log" angegeben, die ausgewertet werden soll, mit "-f" wird bei Erreichen des Dateiendes aber auf neue Einträge gewartet (wie bei tail -f). Die Blacklist-Einträge werden beim Programmstart (so -b ... angegeben wurde) aus Textdateien (Achtung, Angabe von Shell-Globs ans Skript, also beim Shell-Aufruf des Python-Skriptes escapen!) mit Domain-Namen (einer pro Zeile) ausgelesen und in eine Hash-Berkeley-DB geschrieben, ohne "-b" wird eine bereits existierende Berkeley-DB verwendet. Die Berkeley-DB hat fest den Namen blacklist.bdb im aktuellen Verzeichnis der Skriptausführung (vgl. bsddb.hashopen-Aufruf im Python-Skript).
Wir starten das Skript spätestens monatlich mit neuen Conficker-Listen, die im Unterverzeichnis blacklists liegen, neu. Aufruf ist dabei im Home-Verzeichnis eines Nicht-Root-Nutzers, der aber die DNS-Query-Logs lesen kann:
nohup ./dns-log-scan.py -b blacklists/\*.txt -i /var/log/dns-logs/dns_query.log -f -o conficker-hosts.txt &
Den Aufruf haben wir mit Prüfungen in das Shell-Skript start-dns-log-scan.sh ausgelagert (was auf jeden Fall verbesserungswürdig ist).
Die Ergebnisse landen bei uns in der Datei conficker-hosts.txt im Homeverzeichnis. Die Zeilen sind dabei die Tab-getrennten Spalten Client-IP, Datum-Stempel YYYYMMHH-hhmm, Blacklist-Textdatei, Query-Log-Eintrag. Beispielsweise:
für eine Conficker-Infektion (viele wie hier mit wechselnden Domains):
130.75.xx.yy 20110313-2334 blacklists/b_domains_20110313.txt '13-Mar-2011 23:34:01.282 queries: client 130.75.xx.yy#4269: query: mdyzmhd.cn IN A +'
130.75.xx.yy 20110313-2334 blacklists/b_domains_20110313.txt '13-Mar-2011 23:34:01.286 queries: client 130.75.xx.yy#4440: query: tewjtltav.org IN A +'
130.75.xx.yy 20110313-2334 blacklists/b_domains_20110313.txt '13-Mar-2011 23:34:03.252 queries: client 130.75.xx.yy#1438: query: ghldvqr.ws IN A +'
für eine Zeus-Infektion (viele, aber Domains eher gleich bleibend):
130.75.xx.yy 20110307-1919 blacklists/zeus-domains.txt '07-Mar-2011 19:19:53.032 queries: client 130.75.xx.yy#50175: query: ofigalidon.ru IN A +'
für einen Eintrag, der keine Infektion ist (wenige Einträge, gleichbleibende Domain, bei uns wie hier häufig ein Mail-Server):
130.75.2.102 20110307-1530 blacklists/c_domains_20110322.txt '07-Mar-2011 15:30:01.736 queries: client 130.75.2.102#43640: query: rutv.cn IN A +'
Das Home-Verzeichnis des Scan-Nutzers auf unserem DNS-Server enthält folgende Einträge:
blacklist.bdb (erzeugt vom Python-Skript, Blacklist in Berkeley-Hash-DB)
conficker-hosts.txt (Ergebnis-Datei des Python-Skripts)
dns-log-scan.py (Python-Scan-Skript)
start-dns-log-scan.sh (Start-Skript für Scanner)
update-malewaredomains.sh (Skript zum Updaten der Nicht-Conficker-Listen)
blacklists/ (Verzeichnis mit Blacklists in Textform)
blacklists/?_domains_2011????.txt (Blacklist einer Conficker-Variante für einen Tag)
blacklists/domains-cc.txt (C&C-Domains aus Maleware-Domains-Liste)
blacklists/zeus-domains.txt (Domains für ZeuS, vgl. ZeuS-Tracker)
Die Skripte finden Sie in dns-id-conficker.tgz zusammengepackt, die Listen mit den Conficker-Domains in der oben unter Conficker angegebenen Tar-Datei. Die anderen Domain-Listen erzeugt das Update-Skript.
Kein Support
Für diesen Tipp / die Software bzw. Skripte leistet das RRZN keinen Support.

