Hacking mit Python, Teil 2 Wörterbuch-Angriff auf Passwort-Hash

Autor / Redakteur: Dipl. -Ing. Thomas Drilling / Stephan Augsten

Dieser Workshop demonstriert, wie man in Python ein Passwort herausfinden kann. Konkret geht es darum, einen auf irgendeine Weise erlangten Passwort-Hash durch einen Vergleich mit dem MD5-Hash eines gegeben Wörterbucheintrages auf Übereinstimmung zu prüfen.

Anbieter zum Thema

Der zu einem Wort passende Hashwert wurde erfolgreich identifiziert.
Der zu einem Wort passende Hashwert wurde erfolgreich identifiziert.
(Bild: Drilling)

Um in Python einen Dictionary-Angriff auf ein gehashtes Passwort ausführen zu können, wollen wir folgendes gedachtes Szenario annehmen: dabei setzen wir voraus, dass es uns gelungen ist, uns in den Besitz eines Passwort-Hashes zu bringen.

Dies ist nicht in erster Linie ein Hacking-Tutorial, sondern eine Python-Kurs. Etwaige Möglichkeiten, wie sich Angreifer in den Besitz eines solches Hashes bringen, sind im ersten Teil skizziert.

Da wir keinen echten Passwort-Hash gegenprüfen wollen, generieren wir uns einen solchen Hashwert auf MD5generator.de
Da wir keinen echten Passwort-Hash gegenprüfen wollen, generieren wir uns einen solchen Hashwert auf MD5generator.de
(Bild: Drilling / MD5generator.de)

Für dieses Beispiel nutzen wir einfach einen Online-MD5-Generator und erzeugen aus unserem geheimen Passwort „sehrgeheim“ einen Hash „53d9019b2362a736e19ff20550d9fc22“, dem wir die Variable „password_hash“ zuweisen.

Das importierte Modul „hashlib“ erlaubt es unter Python, MD5-Hashes zu berechnen.
Das importierte Modul „hashlib“ erlaubt es unter Python, MD5-Hashes zu berechnen.
(Bild: Drilling)

Für das Berechnen von MD5-Hashes in Python benötigt man das Python-Modul „hashlib“, welches zunächst zu importieren ist. Dieses erlaubt es z. B., den MD5-Hash eines beliebigen Strings zu berechnen. Ein erster Versuch mit ...

hashlib.md5(„Test“)

... offenbart allerdings anhand der angezeigten Fehlermeldung, dass der MD5-Algorithmus in Python nicht auf Zeichen, sondern auf Byte-Ebene arbeitet, d. h. man kann hashlib.md5 nicht direkt einen String übergeben, sondern muss diesen zuvor in die die Byte-Darstellung umwandeln. Das funktioniert wir in unserem Python-Workshop gezeigt mit:

hashlib.md5(„Test“.encode())

Dann funktioniert auch die Ausgabe und das Kommando liefert ein neues Objekt zurück, das den berechneten MD5-Hash repräsentiert. Um den Hash in Byte-Darstellung zu sehen, können wir das Objekt z. B. in einer Variablen „output“ zwischenspeichern und diese dann mit output.digest() in die Byte-Repräsentation unwandeln:

output = hashlib.md5(„Test“.encode())
output.digest()

Optional geht das auch in gewohnter Hex-Darstellung mit

output = hashlib.md5(„Test“.encode())
output.hexdigest()

Das Ganze lässt sich in Python natürlich auch ohne Zwischenvariable in einer Zeile schreiben:

hashlib.md5(„Test“.encode()).hexdigest()

Wir haben damit alle erforderlichen Schritte beisammen, um in Python einen MD5-Hash in gewohnter MD5-Darstellung zu einem gegeben String mit nur einem Befehl zu erzeugen. Der Vollständigkeit halber prüfen wir jetzt noch unseren Befehl auf Übereinstimmung auf den MD5-Hash unseres oben erzeugten Hashes für das Passwort „Test“

Dictionary Angriff auf einen MD5-Hash

Für unseren Dictionary-Angriff bedienen wir uns einer englischen Wortliste und passen dementsprechend auch unseren Test an.
Für unseren Dictionary-Angriff bedienen wir uns einer englischen Wortliste und passen dementsprechend auch unseren Test an.
(Bild: Drilling / MD5generator.de)

Nun können wir uns der eigentlichen Aufgabe zuwenden. Dazu benötigen wir zunächst einmal ein Dictionary. Als Wörterbuch-Quelle für unseren Demo-Angriff verwenden die https://github.com/brannondorsey/naive-hashcat/.../rockyou.txt Rockyou-Wordlist von Github. Da das Projekt auf englischen Wörtern basiert, legen wir als geheimes Test-Passwort „monkey“ fest. Der zugehörige Vergleichs-Hash lautet in diesem Fall: d0763edaa9d9bd2a9516280e9044d885

Nun lesen wir die passende Passwort-Datei C:\\Users\\drilling.THOMAS-DRILLING\\jupyter\\Dev-Insider\\rockyou.txt in Python ein. Das Einlesen gelingt dann mit ...

with open („C:\\Users\\drilling.THOMAS-DRILLING\\jupyter\\Dev-Insider\\rockyou.txt“) as pwdatei:

…, wobei „pwdatei“ die Variable ist, in der wie die Datei speichern und sich der Ausdruck „… with open … as …“ um das korrekte Öffnen und Schließen der Datei kümmert.

Wir weisen Python an, die Wortliste Zeile für Zeile zu durchsuchen.
Wir weisen Python an, die Wortliste Zeile für Zeile zu durchsuchen.
(Bild: Drilling)

Da die Datei nun geöffnet ist, lässt sie sich Zeile für Zeile durchsuchen. Dies erledigen wir in einer for-Schleife, wobei wir die jeweilige Zeile mit print ausgeben können. Da die Datei Tausende von Zeilen enthält, halten wir die Programmausführung gleich nach Ausgabe der ersten Zeile mit „break“ wieder an, also:

with open („C:\\Users\\drilling.THOMAS-DRILLING\\jupyter\\Dev-Insider\\rockyou.txt“) as pwdatei:
   for line in pwdatei:
      print(line)
      break

Wir bekommen als Ausgabe:

123456

Schwer zu erkennen ist, dass das Kommando am Ende der Zeile noch einen Zeilenumbruch mit ausgibt. Zeilenumbrüche werden bekanntlich mit „\n“ maskiert. Um diesen Zeilenumbruch in Python zu entfernen verwenden wir

print(line.strip())

Wollten wir also das Wort „wort“ überprüfen, müssten wir es konkret mittels „line.strip2 ansprechen.

Jetzt müssen wir lediglich in jeder Zeile den Hash mittels Python berechnen und mit dem gegebenen (ggf. abgefangenen oder gestohlenen) Hash (hier: d0763edaa9d9bd2a9516280e9044d885) vergleichen.

Beginnen wir mit der Berechnung der Hash-Werte und geben zunächst jeden berechneten Hash-Wert mit „print“ zur Kontrolle aus.

Ohne break-Kommando müssen wir die Ausgabe in der zugehörigen Notebook-Zelle händisch abbrechen.
Ohne break-Kommando müssen wir die Ausgabe in der zugehörigen Notebook-Zelle händisch abbrechen.
(Bild: Drilling)

with open(„C:\\Users\\drilling.THOMAS-DRILLING\\jupyter\\Dev-Insider\\noun.exc“) as pwdatei:
   for line in pwdatei:
      wort = line.strip()
      print(hashlib.md5(wort.encode()).hexdigest())

Wie erwähnt erwähnt müssten wir entweder die Programmausführung direkt im Code mit einem break-Kommando anhalten oder die Ausgabe in der zugehörigen Notebook-Zelle mit der Stop-Schaltfläche im Editor oder Strg+C abbrechen. Das sähe dann so wie im obigen Bild.

Der zu einem Wort passende Hashwert wurde erfolgreich identifiziert.
Der zu einem Wort passende Hashwert wurde erfolgreich identifiziert.
(Bild: Drilling)

Fehlt nur noch der finale Vergleich mit unserem Kontroll-Passwort-Hash. Findet sich irgendwo im Dictionary tatsächlich eine Übereinstimmung, soll das Wort ausgegeben werden.

with open(„C:\\Users\\drilling.THOMAS-DRILLING\\jupyter\\Dev-Insider\\noun.exc“) as pwdatei:
   for line in pwdatei:
      wort = line.strip()
      if(hashlib.md5(wort.encode()).hexdigest() == „1e6947ac7fb3a9529a9726eb692c8cc5“:
         print(wort)
         break
print“(Geschafft!“)

Fazit

Dieser kleine Einstieg in das Thema Ethical-Hacking mit Hilfe von Python zeigt einerseits, wie einfach und schnell sich Wörterbuch-Angriffe realisieren lassen, wenn das Passwort zu einfach ist, weil es auf einem Wörterbucheintrag basiert. Zweitens haben wir gezeigt, wie mächtig Python im Zusammenhang mit den zahllosen verfügbaren Bibliotheken ist.

Dieser Workshop hat im Kontext unseres Python-Einsteigerworkshop noch keine neuen Befehle oder Kontrollstrukturen verwendet. Die ganze Magie lag in der Mächtigkeit des Moduls hashlib.

(ID:45936390)