- Das Team von Texts.com wollte Meta Messenger für macOS analysieren, eine eigenständige Desktop-App, die der eigenen App ähnelt; Certificate Pinning verhinderte jedoch eine proxybasierte MITM-Analyse
- Metas Certificate Pinning sorgt dafür, dass die App nur zugelassene Zertifikate vertraut, und blockiert damit das Abfangen und Entschlüsseln von Requests über eine vom Nutzer erstellte Zertifizierungsstelle
- Dynamische Instrumentierung mit Frida verursachte bei Messenger Abstürze und war aufwendig zu verteilen, daher wählte das Team einen kleineren, reproduzierbaren Binary Patch
- Die Analyse mit Hopper zeigte: Wenn man 4 Byte so ändert, dass
IsUsingSandbox() true zurückgibt, lässt sich ein Codepfad nutzen, der bei Verwendung einer custom sandbox die SSL-Verifikation abschaltet
- Nach dem Ersetzen des Original-Binaries durch die gepatchte ausführbare Datei und dem Umgang mit der Signierung konnten im Proxy-Tool Header, Response Body und Request-Informationen eingesehen werden
Warum Texts.com Messenger analysiert hat
- Batuhan İçöz, der bei Texts.com für Projekte rund um Meta-Plattformen zuständig ist, hielt die Messenger-App für macOS für analysierenswert, weil sie als eigenständige Desktop-App dem eigenen Modell nahekommt
- Das Abfangen von Netzwerk-Requests hat eine niedrige Einstiegshürde und eignet sich gut als erster Schritt, um das Verhalten einer App zu verstehen
- Meta setzt in der App jedoch Certificate Pinning ein, um das Sicherheitsmodell zu stärken, und blockiert damit sogar MITM-Analysen, die Nutzer gegen sich selbst durchführen
Was Certificate Pinning verhindert
- Um Requests mit einem Proxy-Client abzufangen, muss der Nutzer eine eigene Zertifizierungsstelle einrichten und ihr vertrauen
- Über ein von dieser Zertifizierungsstelle ausgestelltes Zertifikat lassen sich Request-Informationen abfangen und entschlüsseln
- Implementiert ein Dienst Certificate Pinning, akzeptiert die App nur Zertifikate, die von bestimmten Zertifizierungsstellen ausgestellt wurden
- In diesem Fall ist das vom Nutzer erstellte Zertifikat ungültig, sodass sich Requests nicht abfangen lassen
Zustand vor dem Patch und Ziel
- Ohne Abschalten des Certificate Pinning geben alle Requests „Internal Error“ zurück
- In der Proxy-Software erscheint „SSL Handshake Failed“, und der Request-Lebenszyklus läuft nicht vollständig durch
- In diesem Zustand ist es schwierig, den Inhalt der Requests abzuleiten
- Ziel ist es, in Netzwerk-Debugging-Tools Requests, Responses und Header direkt lesen zu können
Fehlgeschlagene Umgehungen und die endgültige Wahl
- Eine früher funktionierende Methode bestand darin, URL-Strings im Binary durch einen selbst gehosteten Endpoint zu ersetzen, der TLS nicht implementiert
- Dieser Endpoint leitet Requests und Responses zwischen Client und Server weiter
- Das eignet sich eher für kleine Apps als für große Apps wie Messenger
- Auch dynamische Instrumentierungsbibliotheken wie Frida kamen infrage, waren bei Messenger aber wenig stabil
- Beim Hooking kam es häufig zu Abstürzen
- Wegen des Overheads war es schwierig, die problematischen Stellen zu finden
- Die zum Ausführen nötige Umgebung und Tool-Konfiguration machen die Verteilung an Teammitglieder kompliziert
- Auch ein über Jahre gepflegtes Frida-Skript wurde ausprobiert
- Dieses Skript wurde für gängige Certificate-Pinning-Bibliotheken und Umgehungsmethoden genutzt und funktionierte bei den meisten Apps
- Metas App-Familie gehörte nicht zu diesen „meisten“
- Schließlich entschied sich das Team dafür, Certificate Pinning per Binary Patch vollständig abzuschalten, weil sich diese Lösung leicht an Teammitglieder weitergeben ließ
Mit Hopper gefundene Patch-Stelle
- Nach dem Download von Messenger und dem Verschieben in den Programme-Ordner wurde das kompilierte ARM-Binary unter
/Applications/Messenger.app/Content/MacOS/Messenger in Hopper importiert
- Hopper kann kompilierte Binaries disassemblieren, dekompilieren, neu kompilieren, debuggen und visualisieren
- Nach dem Laden des Binaries und der Referenzen wurde nach Begriffen wie
certificate, ssl und pinning gesucht
- Der String
"SSL pinning verification failed for host:" wurde zum Ausgangspunkt der Analyse
- Da ein kompiliertes Binary bei zu umfangreichen Änderungen abstürzen kann, wurde eine Strategie mit möglichst kleinen Änderungen gewählt
- Ideal sind Patches mit begrenztem Wirkungsbereich, etwa das Umdrehen eines booleschen Werts, das Invertieren einer Bedingung oder das Ändern weniger Instruktionen
IsUsingSandbox() immer true zurückgeben lassen
- Der Kontrollfluss wurde über einen Control-Flow-Graph visualisiert, und die verbundenen Referenzen wurden nach oben verfolgt
- Dabei wurde der String
"Using custom sandbox -> turn off SSL verification" gefunden
- Die Referenz der Funktion, die dieses Flag bestimmt, wurde in der Datei gesucht und am Anfang der Prozedur identifiziert
- In der Funktion
IsUsingSandbox() wurde die Stelle verfolgt, an der der Rückgabewert zugewiesen wird
- Das Register
w0 wird aus w19 verschoben und anschließend zurückgegeben
w19 wird ursprünglich per load-byte-Instruktion zugewiesen
- Wenn
w19 nicht geladen, sondern immer auf true gesetzt wird, gibt IsUsingSandbox() true zurück
- Dem zuvor gefundenen String zufolge wird bei Verwendung einer custom sandbox die SSL-Verifikation abgeschaltet; durch diese Änderung wird also Certificate Pinning deaktiviert
Original
ARM: ldrb w19, [sp, #0x40 + var_20]
HEX: F3 83 40 39
Rewritten
ARM: mov w19, #1
HEX: 33 00 80 52
- Dieser Austausch wurde im hexadecimal mode durch direktes Ändern des Bytecodes der Anwendung vorgenommen
Ergebnis und erneute Signierung
- Mit Hoppers Option „Produce New Executable“ wurde eine neue ausführbare Datei exportiert
- Nachdem die Signatur der ausführbaren Datei entfernt war, wurde das ursprüngliche Messenger-Binary durch das neue Binary ersetzt
- Nach dem erneuten Start von Messenger waren im Proxy-Tool Header, Response Body und weitere Request-Informationen sichtbar
- Von insgesamt 97.477.728 Byte Binary-Größe reichte die Änderung von 4 Byte, um das Abfangen von Requests zu ermöglichen
- Wer einen ähnlichen Ansatz unter iOS sehen möchte, kann Hassan Mostafas Artikel von 2020 zur Umgehung des Instagram Certificate Pinning lesen
- Der Artikel beschreibt einen Fall, in dem auf einem jailbroken iPhone eine bedingte Sprunginstruktion umgedreht wurde, um Instagram Certificate Pinning zu deaktivieren
- Das kompilierte Binary wurde an Batuhan weitergegeben
- Batuhan beschaffte und installierte ein Signaturzertifikat und signierte anschließend die Anwendung
- Danach konnte er das Binary auf seinem System verwenden, um seine eigenen Requests zu sehen
codesign --force --deep -s CERTNAME_OR_ID /Applications/Messenger.app
1 Kommentare
Hacker-News-Kommentare
Ich war auf einem ähnlichen Weg und habe in dem Moment aufgegeben, als ich dekompilieren/modifizieren/rekompilieren wollte.
Das ist schon Hartnäckigkeit, und ich frage mich, wie viele Stunden tatsächlich hineingeflossen sind. Ich hatte mir eine Abbruchgrenze gesetzt und mich dann auch daran gehalten.
Zuerst habe ich zwei Stunden lang verschiedene Befehle verändert und dann aufgegeben. Später sah ich einen älteren Beitrag des Reverse Engineers „Hassan Mostafa“ (cyclon3), der mit derselben Methode Erfolg hatte – nämlich einen Beitrag über den Einsatz von Hopper Disassembler bei Instagram auf iOS – und habe es an diesem Abend noch einmal versucht, aber ohne Erfolg. Ich habe auch dieselben Befehle gesucht und verändert.
Dann beschloss ich, es gut sein zu lassen, und ein paar Wochen später probierte ich es aus einer Laune heraus mit leichtem Restfrust noch einmal; nachdem ich die Sandbox-Funktion gefunden hatte, war ich etwa 30 Minuten später fertig.
Mit eBPF scheint man Daten vor der TLS-Verschlüsselung lesen zu können: Debugging with eBPF Part 3: Tracing SSL/TLS connections https://blog.px.dev/ebpf-openssl-tracing/
Wenn man den echten App-Traffic über einen Abfang-Proxy routet, spart das je nach Ziel erheblich Zeit. Wenn man zum Beispiel nach der Authentifizierung bzw. Session-Einrichtung automatisch einen Parameter einer Anfrage ändern will, ist es viel schneller, die App den gesamten Anfangsprozess selbst durchlaufen zu lassen und nur an einer Stelle im Proxy etwas zu ändern, statt einen neuen Client zu schreiben, der alles selbst ausführt, oder die Änderungslogik als eBPF-Filter zu implementieren.
rustlsstatisch linken, funktioniert diese Methode nicht.Sehr cleverer Ansatz. Allerdings hätte man Certificate Pinning wahrscheinlich auch im Sandbox-Modus erzwingen können.
Das erinnert mich daran, wie ich im Studium versucht habe, Snapchat per Man-in-the-Middle anzugucken; dort gab es auch Certificate Pinning, und ich habe es am Ende nicht knacken können.
Ich habe nicht einmal den Einstiegspunkt gefunden. Für eine relativ kleine Social-Media-App war die Sicherheit schon 2015 absurd stark.
Selbst wenn im Sandbox-Modus Certificate Pinning verwendet worden wäre, hätte es wahrscheinlich einen anderen Weg gegeben, die Prüfung des angehefteten Zertifikats zu entfernen.
Zumindest früher.
Dieser Beitrag erinnert mich an die +Orc-Zeit. Viel Wissen, das damals üblich war – etwa wie man unerwünschte Branches findet und mit NOPs neutralisiert – scheint inzwischen verloren gegangen zu sein.
Heute gibt es aber auch deutlich mehr Techniken zu lernen, also ist das nachvollziehbar.
[1]: https://en.m.wikipedia.org/wiki/Old_Red_Cracker
Trotzdem gibt es meiner Meinung nach noch viele Leute, die NOP-Patches machen. Es ist nur komplexer geworden. Leute, die DRM knacken oder beliebige Mobile-Apps mit Hex-Editoren und Ähnlichem untersuchen, gibt es weiterhin.
Moderne Programme sind komplexer und dadurch schwerer zugänglich geworden, aber gleichzeitig ist das nötige Wissen heute leichter verfügbar.
Wenn man Meta-App-Traffic abfangen will, muss man gar nicht unbedingt so weit gehen.
https://www.facebook.com/whitehat/bugbounty-education/261571...
Ich frage mich, ob Runtime-Binary-Checksums solche Modifikationen erschwert hätten.
Ist das bei mobilen Apps nicht gängige Praxis? Bieten die iOS- oder Android-SDKs so etwas an? Es wirkt so, als müsste das an den offiziellen Release-Prozess angebunden und dann auf den jeweiligen nicht gejailbreakten Plattformen erzwungen werden.
Ist vielleicht eine grundlegende Frage, aber die endgültige Lösung bestand ja darin, ein paar Bytes im Binärprogramm zu ändern, daher wirkte es grundsätzlich verhinderbar.
Auf nicht gejailbreakten Plattformen geschieht das normalerweise mit einem Entwicklerzertifikat.
Metas Abwehr gegen Reverse Engineering wirkt, zumindest bei Messenger, ziemlich locker.
Auch ohne auf fortgeschrittene Obfuskation zu gehen, hätte es einfach sein können,
IsUsingSandbox()im Produktions-Build komplett zu entfernen.Certificate Pinning sollte es Angreifern schwerer machen, etwas zu manipulieren, nicht Nutzern.
Als ich die App zum ersten Mal geknackt habe, ging ich natürlich davon aus, dass es scheitern würde, aber tatsächlich war es überraschend einfach, solche leicht zu modifizierenden JNE/JEZ-Stellen zu finden.
Selbst wenn man die falsche auswählt, kann man einfach zur Originaldatei zurückkehren und eine andere Stelle ausprobieren.
So etwas müsste sich mit AI doch leicht automatisieren lassen. Man müsste nur an mehreren Kandidatenstellen JEZ/JNZ umdrehen, die App starten und schauen, ob der nervige Screen erscheint.
Wenn die Fehlerbedingung sauber definiert ist, muss man letztlich nur die Kandidaten eingrenzen.
Wenn AI Denuvo ignorierend im Nullschussverfahren knacken könnte, wäre das noch einmal etwas anderes.
Ich frage mich, warum die Anwendung eines so großen Unternehmens nicht vollständig obfuskiert ist und auch nicht genug Schutzmechanismen enthält, um die Ausführung modifizierter Binärdateien zu verhindern
Einzelpersonen, Gruppen oder Regierungen, die ausreichend kompetent oder stark genug motiviert sind, kommen am Ende ohnehin durch. So ist es nun einmal, wenn man Client-Binärdateien verteilt.
Man kann enorm viel Zeit und Geld darauf verwenden, es zu verhindern. Früher wollte Pinterest einmal eine eigene Sprache und virtuelle Maschine ausliefern, und ich war dagegen. Oder man akzeptiert einfach, dass Client-Code im Grunde bereits kompromittiert ist, legt die Logik auf den Server und macht weiter.
Certificate Pinning ist fast kostenlos und eher eine Maßnahme nach dem Motto „Einsteigen nur mit diesem Schlüssel oder besser“. Es ist nicht sicher, filtert aber allerlei nebenbei unternommene Versuche heraus
Natürlich hat es auch Einfluss auf Reverse Engineering, aber das ist eher ein Nebeneffekt.
Letztlich läuft der Code auf dem Gerät des Nutzers, und der Nutzer kann beobachten, was der Code tut, daher ist Deobfuskation jederzeit möglich. Wenn eine Person es einmal entschlüsselt und das Ergebnis teilt, lässt es sich auch sehr leicht vervielfältigen. Das heißt nicht, dass Obfuskation nutzlos ist, aber es ist nichts, worauf man übermäßig viel Zeit verwenden sollte
Wenn ein Angreifer physischen Zugriff auf das Gerät hat, gibt es ab diesem Zeitpunkt keine Möglichkeit mehr, ihn aufzuhalten. Man kann den Prozess nur lästiger machen und hoffen, dass er genervt aufgibt
Obfuskation hätte das Ergebnis dieses Experiments kaum beeinflusst, allenfalls hätte sich der Ansatz dahin verschoben, etwas mehr dynamische Instrumentierung zu verwenden. Die wirksamste Obfuskation, die ich gesehen habe, war VM-Obfuskation, aber die Leistungseinbußen sind erheblich. Obfuskation erschwert auch normales Debugging.
Der Schutz vor modifizierten Binärdateien findet auf Systemebene statt, kann aber auch auf Anwendungsebene implementiert werden und ist dort ebenfalls verbreitet. Allerdings kann auch diese Funktion umgangen werden, und nach Abschluss der Sicherheitsprüfungen kann man mit dynamischen Instrumentierungsbibliotheken wie Frida Änderungen vornehmen.
Aus Sicht von Meta scheint es nicht die beste Verwendung der Ressourcen zu sein, mit Reverse Engineers ein Katz-und-Maus-Spiel zu spielen
Ich frage mich, welches Proxy-Tool im Artikel verwendet wurde. Wird der gesamte Anwendungsverkehr während der Laufzeit dorthin geleitet?
Entschuldigung, falls das eine dumme Frage ist
Unter macOS lässt sich der gesamte Datenverkehr aller Anwendungen dorthin leiten, und wenn man auf dem Gerät ein selbstsigniertes Zertifikat installiert und sich mit dem Proxy verbindet, kann man auch iOS-Geräte darüber proxien