Flutter

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Flutter es el kit de UI multiplataforma de Google que permite a los desarrolladores escribir una única base de código Dart que el Engine (native C/C++) transforma en código máquina específico para Android e iOS. El Engine incluye un Dart VM, BoringSSL, Skia, etc., y se distribuye como la librería compartida libflutter.so (Android) o Flutter.framework (iOS). Todo el networking real (DNS, sockets, TLS) ocurre dentro de esta librería, no en las capas habituales Java/Kotlin o Swift/Obj-C. Ese diseño aislado es la razón por la que los hooks habituales a nivel Java con Frida fallan en apps Flutter.

Interceptar tráfico HTTPS en Flutter

This is a summary of this blog post.

Por qué interceptar HTTPS es complicado en Flutter

  • La verificación SSL/TLS vive dos capas abajo en BoringSSL, por lo que los bypasses de SSL‐pinning a nivel Java no lo afectan.
  • BoringSSL usa su propio almacén de CA dentro de libflutter.so; importar tu Burp/ZAP CA en el store del sistema Android no cambia nada.
  • Los símbolos en libflutter.so están stripped & mangled, ocultando la función de verificación de certificados a herramientas dinámicas.

Identificar la pila Flutter exacta

Conocer la versión te permite reconstruir o buscar patrones en los binarios correctos.

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 – un único true es suficiente para bypassear toda la comprobación de la cadena de certificados.
  • La misma función existe en todas las arquitecturas CPU; solo difieren los opcodes.

Opción A – Parcheo binario con reFlutter

  1. Clone los sources exactos del Engine & Dart para la versión Flutter de la app.
  2. Regex-patch dos hotspots:
  • En ssl_x509.cc, forzar return 1;
  • (Opcional) En socket_android.cc, hard-codear un proxy ("10.0.2.2:8080").
  1. Re-compile libflutter.so, reemplazarla en el APK/IPA, firmar, instalar.
  2. Pre-patched builds para versiones comunes se distribuyen en los releases de reFlutter en GitHub para ahorrar horas de compilación.

Opción B – Hooking en vivo con Frida (la vía “hard-core”)

Porque el símbolo está strippeado, haces pattern-scan del módulo cargado buscando sus primeros bytes y luego cambias el valor de retorno en caliente.

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

Por favor, proporciona el contenido de src/mobile-pentesting/android-app-pentesting/flutter.md que quieres que traduzca al español, o pega el texto aquí.

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

Consejos para portar

  • 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.

Forzar el tráfico a través de tu proxy

Flutter itself ignores device proxy settings. Easiest options:

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

Flujo rápido de TLS bypass para 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. Instala tu proxy CA en el almacén del sistema. Sigue Install Burp Certificate para hashear/renombrar el certificado DER de Burp y empujarlo a /system/etc/security/cacerts/ (writable /system required).

  2. Coloca un binario frida-server coincidente y ejecútalo como root para que pueda adjuntarse al proceso de Flutter:

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. Instala las herramientas del lado del host y enumera el paquete objetivo.
pip3 install frida-tools --break-system-packages
adb shell pm list packages -f | grep target
  1. Inicia la app Flutter con el hook de Codeshare que neutraliza las comprobaciones de pin de BoringSSL.
frida -U -f com.example.target --codeshare TheDauntless/disable-flutter-tls-v1 --no-pause

El script Codeshare anula el verificador TLS de Flutter, por lo que se acepta cualquier certificado (incluidos los generados dinámicamente por Burp), eludiendo las public-key pin comparisons.

  1. Ruta el tráfico a través de tu proxy. Configura la GUI del proxy Wi‑Fi del emulador o fíjalo mediante adb shell settings put global http_proxy 10.0.2.2:8080; si el enrutamiento directo falla, recurre a adb reverse tcp:8080 tcp:8080 o a un host-only VPN.

  2. Si la app ignora los ajustes de proxy del OS, redirige los sockets con un shim de Frida. Herramientas como frida4burp hook dart:io/BoringSSL socket creation para forzar que las sesiones TCP salientes usen tu proxy, incluso con HttpClient.findProxyFromEnvironment hardcodeado o bypasses de Wi‑Fi. Configura el host/puerto del proxy en el script y ejecútalo junto con el bypass TLS:

frida -U -f com.example.target --no-pause \
--codeshare TheDauntless/disable-flutter-tls-v1 \
-l frida4burp.js

Funciona en iOS mediante un Frida gadget o USB frida-server; encadenar el socket redirect con el bypass de TLS restaura tanto el enrutamiento como la aceptación de certificados para Burp/mitmproxy.

Una vez que la CA es confiada a nivel del OS y Frida anula la lógica de pinning de Flutter (más socket redirection si es necesario), Burp/mitmproxy recupera visibilidad completa para API fuzzing (BOLA, token tampering, etc.) sin volver a empaquetar el APK.

Hook basado en offset de la verificación de BoringSSL (no signature scan)

Cuando los scripts basados en patrones fallan entre arquitecturas (p. ej., x86_64 vs ARM), engancha directamente el verificador de chain de BoringSSL por dirección absoluta dentro de libflutter.so. Flujo de trabajo:

  • Extrae la librería con la ABI correcta del APK: unzip -j app.apk "lib/*/libflutter.so" -d libs/ y elige la que coincida con el dispositivo (p. ej., lib/x86_64/libflutter.so).
  • Analízala en Ghidra/IDA y localiza el verificador:
  • Fuente: BoringSSL ssl_x509.cc función ssl_crypto_x509_session_verify_cert_chain (3 args, devuelve bool).
  • En builds stripped, usa Search → For Strings → ssl_client → XREFs, luego abre cada FUN_... referenciado y selecciona el que tenga 3 args tipo puntero y un retorno booleano.
  • Calcula el offset en tiempo de ejecución: toma la dirección de la función mostrada por Ghidra y réstale la image base (p. ej., Ghidra suele mostrar 0x00100000 para PIE Android ELFs). Ejemplo: 0x02184644 - 0x00100000 = 0x02084644.
  • Engancha en tiempo de ejecución usando base + offset y fuerza el éxito:
// 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);

Notas

  • Los Signature scans pueden tener éxito en ARM pero fallar en x86_64 porque cambia la disposición de los opcodes; este método de offset es agnóstico a la arquitectura siempre que recalcules el RVA.
  • Este bypass hace que BoringSSL acepte cualquier chain, permitiendo HTTPS MITM independientemente de los pins/CA de confianza dentro de Flutter.
  • Si enrutas forzosamente el tráfico durante el debugging para confirmar el bloqueo TLS, por ejemplo:
iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination <Burp_IP>:<Burp_Port>

…todavía necesitarás el hook anterior, ya que la verificación ocurre dentro de libflutter.so, no en Android’s system trust store.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks