Flutter

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Flutter is Google’s cross-platform UI toolkit that lets developers write a single Dart code-base which the Engine (native C/C++) turns into platform-specific machine code for Android & iOS. The Engine bundles a Dart VM, BoringSSL, Skia, etc., and ships as the shared library libflutter.so (Android) or Flutter.framework (iOS). All actual networking (DNS, sockets, TLS) happens inside this library, not in the usual Java/Kotlin Swift/Obj-C layers. That siloed design is why the usual Java-level Frida hooks fail on Flutter apps.

Intercepting HTTPS traffic in Flutter

This is a summary of this blog post.

Why HTTPS interception is tricky in Flutter

  • SSL/TLS verification lives two layers down in BoringSSL, so Java SSL‐pinning bypasses don’t touch it.
  • BoringSSL uses its own CA store inside libflutter.so; importing your Burp/ZAP CA into Android’s system store changes nothing.
  • Symbols in libflutter.so are stripped & mangled, hiding the certificate-verification function from dynamic tools.

Fingerprint the exact Flutter stack

Knowing the version lets you re-build or pattern-match the right binaries.

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 – a single true is enough to bypass the whole certificate chain check.
  • Same function exists on every CPU arch; only the opcodes differ.

Option A – Binary patching with reFlutter

  1. Clone the exact Engine & Dart sources for the app’s Flutter version.
  2. Regex-patch two hotspots:
  • In ssl_x509.cc, force return 1;
  • (Optional) In socket_android.cc, hard-code a proxy ("10.0.2.2:8080").
  1. Re-compile libflutter.so, drop it back into the APK/IPA, sign, install.
  2. Pre-patched builds for common versions are shipped in the reFlutter GitHub releases to save hours of build time.

### Option B – Live hooking with Frida (the “hard-core” path) Because the symbol is stripped, you pattern-scan the loaded module for its first bytes, then change the return value on the fly.

// 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"); }
});

Nie mam dostępu do plików. Wklej zawartość pliku src/mobile-pentesting/android-app-pentesting/flutter.md tutaj, a przetłumaczę ją na polski, zachowując dokładnie markdown/HTML oraz nie tłumacząc kodu, linków, ścieżek i tagów.

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

Wskazówki dotyczące portowania

  • For arm64-v8a or armv7, grab the first ~32 bytes of the function from Ghidra, convert to a space-separated hex string, and replace sig.
  • Keep one pattern per Flutter release, store them in a cheat-sheet for fast reuse.

Wymuszanie ruchu przez proxy

Flutter itself ignores device proxy settings. Easiest options:

  • Android Studio emulator: Settings ▶ Proxy → manual.
  • Urządzenie fizyczne: evil Wi-Fi AP + DNS spoofing, or Magisk module editing /etc/hosts.

Szybki workflow obchodzenia TLS w Flutter (Frida Codeshare + system CA)

When you only need to observe a pinned Flutter API, combining a rooted/writable AVD, a system-trusted proxy CA, and a drop-in Frida script is often faster than reverse-engineering libflutter.so:

  1. Install your proxy CA in the system store. Follow Install Burp Certificate to hash/rename Burp’s DER certificate and push it into /system/etc/security/cacerts/ (writable /system required).

  2. Drop a matching frida-server binary and run it as root so it can attach to the Flutter process:

adb push frida-server-17.0.5-android-x86_64 /data/local/tmp/frida-server
adb shell "su -c 'chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &'"
  1. Zainstaluj narzędzia po stronie hosta i przeprowadź enumerację docelowego pakietu.
pip3 install frida-tools --break-system-packages
adb shell pm list packages -f | grep target
  1. Uruchom aplikację Flutter z Codeshare hook, który neutralizuje BoringSSL pin checks.
frida -U -f com.example.target --codeshare TheDauntless/disable-flutter-tls-v1 --no-pause

Skrypt Codeshare nadpisuje Flutter TLS verifier, więc każdy certyfikat (w tym dynamicznie generowane przez Burp) jest akceptowany, omijając weryfikacje pinowania klucza publicznego.

  1. Przekieruj ruch przez swój proxy. Skonfiguruj proxy Wi‑Fi emulatora przez GUI lub wymuś je za pomocą adb shell settings put global http_proxy 10.0.2.2:8080; jeśli bezpośrednie routowanie zawiedzie, użyj adb reverse tcp:8080 tcp:8080 lub host-only VPN.

Gdy CA jest zaufany na warstwie OS i Frida stłumi logikę pinowania Fluttera, Burp/mitmproxy odzyskuje pełną widoczność do fuzzingu API (BOLA, manipulacja tokenami itp.) bez repackowania APK.

Hook oparty na offsetcie w weryfikacji BoringSSL (bez skanowania sygnatur)

Gdy skrypty oparte na wzorcach zawodzą między architekturami (np. x86_64 vs ARM), podłącz się bezpośrednio do weryfikatora łańcucha BoringSSL przez adres absolutny w libflutter.so. Przebieg:

  • Wypakuj bibliotekę dla odpowiedniego ABI z APK: unzip -j app.apk "lib/*/libflutter.so" -d libs/ i wybierz tę odpowiadającą urządzeniu (np. lib/x86_64/libflutter.so).
  • Przeanalizuj w Ghidra/IDA i zlokalizuj weryfikator:
  • Źródło: BoringSSL ssl_x509.cc function ssl_crypto_x509_session_verify_cert_chain (3 args, returns bool).
  • W buildach ze strippingiem użyj Search → For Strings → ssl_client → XREFs, następnie otwórz każdą referencjonowaną funkcję FUN_... i wybierz tę z 3 argumentami przypominającymi wskaźniki i zwracającą boolean.
  • Oblicz offset w czasie wykonania: weź adres funkcji pokazany przez Ghidra i odejmij image base (np. Ghidra często pokazuje 0x00100000 dla PIE Android ELF). Przykład: 0x02184644 - 0x00100000 = 0x02084644.
  • Ustaw hook w czasie wykonywania na base + offset i wymuś powodzenie:
// 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);

Notatki

  • Skanowania sygnatur mogą powieść się na ARM, ale nie wykryć na x86_64, ponieważ układ opcode’ów się zmienia; ta metoda z przesunięciem jest niezależna od architektury, o ile przeliczysz RVA.
  • To obejście powoduje, że BoringSSL akceptuje dowolny chain, umożliwiając HTTPS MITM niezależnie od pins/CA trust wewnątrz Flutter.
  • Jeśli wymusisz przekierowanie ruchu podczas debugowania, aby potwierdzić blokowanie TLS, np.:
iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination <Burp_IP>:<Burp_Port>

…wciąż będziesz potrzebować powyższego hooka, ponieważ weryfikacja odbywa się wewnątrz libflutter.so, a nie Android’s system trust store.

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks