Verteiltes berechnen von Passwörtern mit John The Ripper

Zur Zeit habe ich drei Server mit je zwei Intel Xeon X5450 3,00 GHz hier zu liegen. Das macht in der Gesamtzahl 24 Cores. Diese geballte Leistung habe ich mal für einen Versuch genutzt, das bekannte Password Recovery Tool john (the ripper) mit Hilfe von OpenMPI auf allen drei Nodes laufen zu lassen und so einen Cluster zu bilden.

Als Betriebssystem verwende ich auf allen Servern Ubuntu 14.04 LTS x64.

benötigte Pakete installieren:

ggf. müsst ihr noch sudo vor den Befehl schreiben, wenn ihr nicht root seid.

apt-get install libopenmpi-dev openmpi-bin libssl-dev make

John The Ripper runterladen:

Die aktuelle Version findet ihr auf http://www.openwall.com/john/ Achtung: ihr müsst die jumbo-Variante runterladen (das ist die Community Edition), nicht die aktuelle öffentliche, da diese keinen MPI-Support hat. http://download.openwall.net/pub/projects/john/1.7.9/john-1.7.9-jumbo-7.tar.gz

John entpacken und Makefile editieren:

tar xzf john-1.7.9-jumbo-7.tar.gz
cd john-1.7.9-jumbo-7/src
nano Makefile

Hier kommentiert ihr die beiden folgenden Zeilen ein:

CC = mpicc -DHAVE_MPI -DJOHN_MPI_BARRIER -DJOHN_MPI_ABORT
MPIOBJ = john-mpi.o

John mit MPI-Support kompilieren:

make linux-x86-64 (für 64-bit i386)
make linux-x86-sse2 (für 32-bit i386)

John testen:

cd ../run
./john --test

John wird nun den Benchmark-Test mit einem CPU-Kern beginnen.
Als nächstes wollen wir versuchen, ob wir es mit MPI nicht doch ein bisschen schneller hinbekommen. Die Syntax lautet wie folgt:

mpirun -np [Anzahl CPU-Kerne des PCs] ./john --test

In meinem Beispiel sind es zwei CPUs mit je 4 Kernen:

mpirun -np 8 ./john --test

Wenn jetzt eine signifikantere Verbesserung der erreichten Werte eintritt, arbeitet MPI wie gewünscht.

John im Cluster nutzen

Bisher haben wir MPI nur auf einem Host genutzt, um mehrere Prozesse miteinander kommunizieren zu lassen. Das eigentliche Aufgabenfeld von MPI ist jedoch die Kommunikation zwischen mehreren Hosts. Zur Kommunikation wird ein Host genutzt, alle anderen Hosts sind Clients. Zur Kommunikation untereinander werden SSH-Keys verwendet.

Vorarbeit I: SSH-Keys erstellen und verteilen

SSH-Keys sind eine tolle Sache, einmal übertragen kann man sich bequem ohne Passwort einloggen. Diese Eigenschaft machen wir uns zu Nutze. Der folgende Befehl muss auf dem Server-Host ausgeführt werden, um einen solchen Schlüssel zu erstellen:

ssh-keygen -t rsa

Wichtig hierbei ist, KEIN Passwort für den Schlüssel zu vergeben. Im Anschluss wird der Schlüssel auf alle Hosts kopiert, auch den Server (da er sich selbst auch via ssh aufruft als Client in meinem Setup). Die IP steht in diesem Beispiel für meinen ersten Host:

ssh-copy-id 192.168.2.71

Zum testen der Verbindung könnt ihr euch nun vom Server-Host aus auf die anderen Hosts via ssh einloggen. Wenn ihr kein Passwort eingeben müsst, funktioniert alles.

Vorarbeit II: feste IPs vergeben

Bei DHCP-zugewiesenen IP-Adressen kann es passieren, dass sie sich manchmal ändern, daher solltet ihr (wenn ihr die MACs der Hosts nicht gerade im DHCP-Server festschreibt) unbedingt feste IP-Adressen nutzen. Dazu müsst ihr (unter Ubuntu/Debian) die Datei /etc/network/interfaces für jeden Host mit einer eigenen IP-Adresse wie folgt editieren (Beispiel):

auto eth0
iface eth0 inet static
        address 192.168.2.71
        netmask 255.255.255.0
        gateway 192.168.2.1
        dns-nameservers 192.168.2.1

Damit die Hosts sich auch unter einem Namen ansprechen können, ergänzen wir diese auch in der Datei /etc/hosts auf allen Hosts:

192.168.2.71 compute1
192.168.2.72 compute2
192.168.2.73 compute3

Nach einem Neustart sind alle Einstellungen übernommenn und ihr könnt mit einem

ping compute1

von einem der Hosts aus testen, ob die Verbindung funktioniert.

MPI-Cluster

Nach der Vorarbeit geht es jetzt ans Werk. Erstellt dazu auf dem Server-Host eine Datei nodes.txt im run-Ordner von john (john-1.7.9-jumbo-7/run) und tragt dort alle beteiligten Hosts ein:

compute1 slots=8
compute2 slots=8
compute3 slots=8

Die Anzahl der Slots gibt an, wie viele CPU-Kerne der Host zur Verfügung hat bzw wie viele Threads er bearbeiten kann. In meinem Fall sind es 2×4 Kerne.
Für einen Test können wir nun einen MPI-Befehl mit der maximalen Anzahl verfügbarer Kerne starten:

mpirun -np 24 -hostfile nodes.txt ./john --test

Ich hatte an dieser Stelle eine Fehlermeldung. Sie besagt, dass keine Infiniband-Verbindung gefunden wurde und auf das verhältnismäßig langsame normale Ethernet-Netzwerk umsteigen muss und stellt kein Problem dar.

--------------------------------------------------------------------------
[[56373,1],0]: A high-performance Open MPI point-to-point messaging module
was unable to find any relevant network interfaces:

Module: OpenFabrics (openib)
  Host: compute1

Another transport will be used instead, although this may result in
lower performance.
--------------------------------------------------------------------------

Auch die danach folgende Nachricht stellt keinen Fehler dar.

[compute1:20091] 23 more processes have sent help message help-mpi-btl-base.txt / btl:no-nics
[compute1:20091] Set MCA parameter "orte_base_help_aggregate" to 0 to see all help / error messages

Sie sagt lediglich aus, dass alle anderen Threads ebenfalls diese Nachricht ausgeben (btl:no-nics) und lässt sich durch ergänzen von „-mca orte_base_help_aggregate 0“ zwischen mpirun und -np entfernen.

Für einen realen Test können wir am Ende versuchen, unsere eigene Passwort-Datei auf dem Server zu attackieren.

Exkurs: Passwortdatei extrahieren

Da die Datei, die unter Linux die Passwörter speichert (/etc/passwd), normalerweise versteckt ist, müssen wir sie erst umwandeln. Dazu befindet sich ebenfalls im run-Ordner das Programm unshadow. Zum ausführen werden zwingend root-Rechte benötigt:

./unshadow /etc/passwd /etc/shadow > mypasswd

Diese Datei können wir nun als Angriffsziel nehmen.

Realszenario: Angriff auf einen Passworthash

Der folgende Befehl lässt john auf klassische Art mit einem Thread arbeiten:

./john mypasswd

Für eine parallele Ausführung ergänzen wir einfach die MPI-Umgebung und versuchen uns mit einer wordlist, welche praktischerweise ebenfalls im run-Ordner befindet (password.lst). Wenn ihr eine andere Wordlist nutzen wollt, muss diese auf alle beteiligten Hosts kopiert werden und zwar in den selben Ordner!

mpirun -mca orte_base_help_aggregate 0 -np 24 -hostfile nodes.txt ./john mypasswd --session=sessionname --wordlist=password.lst

Da die Liste nur rund 3300 Einträge lang ist, wird sie bei mir innerhalb weniger Sekunden abgearbeitet, sodass ihr nicht lange auf ein Ergebnis warten müsstet. Da euer Passwort, welches ihr natürlich nach allen Sicherheitsregeln erstellt habt 😉 höchstwahrscheinlich nicht in der wordlist.lst vorhanden ist, könnt ihr es einfach in diese am Ende hinzufügen (und daran denken, dass dies auf allen Hosts geändert werden muss) und schauen, ob es von john gefunden wird. Um herauszufinden, welche Passwörter john bereits aus einer Datei extrahiert hat, genügt der folgende Befehl:

./john --show mypasswd

Wenn ihr andere Hashes habt, müssen diese ebenfalls in eine Datei geschrieben werden. Hierzu gibt es ein paar nützliche Hilfen bzgl. der richtigen Formatierung auf dieser Seite.
Zum Abschluss soll noch gesagt werden, dass es zwar prinzipiell möglich ist, einen Bruteforce-Angriff mit john zu machen, dieser aber höchstwahrscheinlich nicht erfolgreich sein wird, da selbst die Rechenleistung mehrerer Hosts nicht ausreichen wird, um euch das gewünschte Ergebnis noch in diesem Leben liefern zu können 😉 Für weitere Parameter verweise ich auf die offizielle Doku: http://openwall.com/john/doc/ welche noch ein paar interessante Kniffe und Tricks liefert, wie zum Beispiel die Wiederaufnahme unterbrochener Sessions.

Stay tuned, Støertebeker

Getagged mit:
Veröffentlicht unter Installationen, Linux, Netzwerk, Security/Hacking, Tutorials

Schreibe einen Kommentar