Flutter

Reading time: 6 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Flutter ist Google’s cross-platform UI toolkit, das Entwicklern erlaubt, eine einzige Dart-Codebasis zu schreiben, die die Engine (native C/C++) in plattformspezifischen Maschinencode für Android & iOS übersetzt. Die Engine bündelt eine Dart VM, BoringSSL, Skia usw. und wird als Shared Library libflutter.so (Android) oder Flutter.framework (iOS) ausgeliefert. Alle eigentlichen Netzwerkoperationen (DNS, sockets, TLS) passieren innerhalb dieser Bibliothek, nicht in den üblichen Java/Kotlin Swift/Obj-C-Schichten. Dieses siloartige Design ist der Grund, warum die üblichen Java-Level Frida-Hooks bei Flutter-Apps versagen.

Intercepting HTTPS traffic in Flutter

Dies ist eine Zusammenfassung dieses blog post.

Why HTTPS interception is tricky in Flutter

  • SSL/TLS verification lebt zwei Ebenen tiefer in BoringSSL, deshalb greifen Java-SSL‑Pinning-Bypässe nicht.
  • BoringSSL verwendet seinen eigenen CA-Store innerhalb von libflutter.so; das Importieren deiner Burp/ZAP CA in den Android-Systemstore ändert nichts.
  • Symbole in libflutter.so sind stripped & mangled, wodurch die Zertifikatsprüfungsfunktion für dynamische Tools verborgen wird.

Fingerprint the exact Flutter stack

Die genaue Version zu kennen erlaubt, die richtigen Binaries nachzubauen oder per Pattern-Matching zu identifizieren.

StepCommand / FileOutcome
Get snapshot hashpython3 get_snapshot_hash.py libapp.soadb4292f3ec25…
Map hash → Engineenginehash list in reFlutterFlutter 3 · 7 · 12 + engine commit 1a65d409…
Pull dependent commitsDEPS file in that engine commitdart_revision → Dart v2 · 19 · 6
dart_boringssl_rev → BoringSSL 87f316d7…

Find get_snapshot_hash.py here.

Target: ssl_crypto_x509_session_verify_cert_chain()

  • Located in ssl_x509.cc inside BoringSSL.
  • Returns bool – ein einziges true reicht aus, um die gesamte Zertifikatskettenprüfung zu umgehen.
  • Dieselbe Funktion existiert auf jeder CPU-Architektur; nur die Opcodes unterscheiden sich.

Option A – Binärpatching mit reFlutter

  1. Clone die exakten Engine- & Dart-Quellen für die Flutter-Version der App.
  2. Regex-patch zwei Hotspots:
  • In ssl_x509.cc, erzwinge return 1;
  • (Optional) In socket_android.cc, einen Proxy hart kodieren ("10.0.2.2:8080").
  1. Re-compile libflutter.so, ersetze sie im APK/IPA, signiere, installiere.
  2. Vorab-gepatchte Builds für gängige Versionen werden in den reFlutter GitHub releases bereitgestellt, um Stunden an Build-Zeit zu sparen.

### Option B – Live hooking mit Frida (the “hard-core” path) Weil das Symbol stripped ist, pattern-scannst du das geladene Modul nach seinen ersten Bytes und änderst dann zur Laufzeit den Rückgabewert.

javascript
// attach & locate libflutter.so
var flutter = Process.getModuleByName("libflutter.so");

// x86-64 pattern of the first 16 bytes of ssl_crypto_x509_session_verify_cert_chain
var sig = "55 41 57 41 56 41 55 41 54 53 48 83 EC 38 C6 02";

Memory.scan(flutter.base, flutter.size, sig, {
onMatch: function (addr) {
console.log("[+] found verifier at " + addr);
Interceptor.attach(addr, {
onLeave: function (retval) { retval.replace(0x1); }  // always 'true'
});
},
onComplete: function () { console.log("scan done"); }
});

Bitte den Inhalt der Datei src/mobile-pentesting/android-app-pentesting/flutter.md hier einfügen — dann übersetze ich ihn ins Deutsche.

bash
frida -U -f com.example.app -l bypass.js

Tipps zum Portieren

  • Für arm64-v8a oder armv7, entnehme die ersten ~32 Bytes der Funktion aus Ghidra, konvertiere sie in einen durch Leerzeichen getrennten Hex-String und ersetze sig.
  • Behalte ein Pattern pro Flutter-Release, speichere sie in einem Cheat-Sheet für schnellen Wiedergebrauch.

Erzwingen des Traffics über deinen Proxy

Flutter selbst ignoriert die Proxy-Einstellungen des Geräts. Einfachste Optionen:

  • Android Studio emulator: Einstellungen ▶ Proxy → manuell.
  • Physisches Gerät: evil Wi-Fi AP + DNS-Spoofing, oder Magisk-Modul, das /etc/hosts bearbeitet.

Offset-basierter Hook der BoringSSL-Verifikation (kein Signature-Scan)

Wenn pattern-basierte Skripte über Architekturen hinweg fehlschlagen (z. B. x86_64 vs ARM), setze einen direkten Hook auf den BoringSSL-Chain-Verifier über die absolute Adresse innerhalb von libflutter.so. Ablauf:

  • Extrahiere die passende ABI-Library aus dem APK: unzip -j app.apk "lib/*/libflutter.so" -d libs/ und wähle diejenige, die zum Gerät passt (z. B. lib/x86_64/libflutter.so).
  • Analysiere in Ghidra/IDA und lokalisere den Verifier:
  • Quelle: BoringSSL ssl_x509.cc Funktion ssl_crypto_x509_session_verify_cert_chain (3 Argumente, gibt bool zurück).
  • In stripped Builds, suche nach dem String "ssl_client" und untersuche XREFs; identifiziere die Funktion, die drei Pointer-ähnliche Argumente nimmt und einen booleschen Wert zurückgibt.
  • Berechne den Runtime-Offset: nimm die von Ghidra angezeigte Funktionsadresse und subtrahiere die während der Analyse verwendete Image-Base, um den relativen Offset (RVA) zu erhalten. Beispiel: 0x02184644 - 0x00100000 = 0x02084644.
  • Hooke zur Laufzeit bei base + offset und erzwinge Erfolg:
javascript
// frida -U -f com.target.app -l bypass.js --no-pause
const base = Module.findBaseAddress('libflutter.so');
// Example offset from analysis. Recompute per build/arch.
const off  = ptr('0x02084644');
const addr = base.add(off);

// ssl_crypto_x509_session_verify_cert_chain: 3 args, bool return
Interceptor.replace(addr, new NativeCallback(function (a, b, c) {
return 1; // true
}, 'int', ['pointer', 'pointer', 'pointer']));

console.log('[+] Hooked BoringSSL verify_cert_chain at', addr);

Hinweise

  • Berechne den Offset für jeden Ziel-Build und jede CPU-Architektur neu; Compiler-/Codegen-Unterschiede brechen hartcodierte Signaturen.
  • Dieser Bypass veranlasst BoringSSL, jede Zertifikatskette zu akzeptieren und ermöglicht damit HTTPS MITM, unabhängig von pins/CA trust innerhalb von Flutter.
  • Wenn du den Traffic während des Debuggings zwangsweise weiterleitest, um TLS-Blocking zu bestätigen, z. B.:
bash
iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination <Burp_IP>:<Burp_Port>

…Sie benötigen dennoch den obigen Hook, da die Überprüfung innerhalb von libflutter.so und nicht im Android’s system trust store stattfindet.

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks