Flutter

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

FlutterはGoogleのクロスプラットフォームUIツールキットで、開発者は単一のDartコードベースを書き、それをEngine(ネイティブC/C++)がAndroid & iOS向けのプラットフォーム固有の機械語に変換します。
EngineにはDart VMBoringSSL、Skiaなどが含まれ、共有ライブラリとしてlibflutter.so(Android)またはFlutter.framework(iOS)で配布されます。実際のネットワーキング(DNS、ソケット、TLS)はすべてこのライブラリ内で行われ、通常のJava/KotlinやSwift/Obj-C層ではありません。そのサイロ化された設計のため、通常のJavaレベルのFridaフックはFlutterアプリでは失敗します。

Intercepting HTTPS traffic in Flutter

これはこの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
手順コマンド / ファイル結果
スナップショットハッシュを取得python3 get_snapshot_hash.py libapp.soadb4292f3ec25…
ハッシュをEngineにマップenginehash list in reFlutterFlutter 3 · 7 · 12 + engine commit 1a65d409…
依存コミットを取得DEPS file in that engine commitdart_revision → Dart v2 · 19 · 6
dart_boringssl_rev → BoringSSL 87f316d7…

スクリプトは 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"); }
});

ファイルの内容(src/mobile-pentesting/android-app-pentesting/flutter.md)を貼り付けてください。受け取り次第、指定どおりマークダウン・タグを保持して英語本文を日本語に翻訳します。

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

移植のヒント

  • arm64-v8a または armv7 の場合、Ghidra から関数の最初の約32バイトを抜き出し、スペース区切りの16進文字列に変換して sig を置き換える。
  • one pattern per Flutter release を維持し、再利用のためにチートシートに保存する。

トラフィックをプロキシ経由に強制する

Flutter 自体は デバイスのプロキシ設定を無視する。簡単な方法:

  • Android Studio エミュレータ: Settings ▶ Proxy → manual.
  • 実機: evil Wi-Fi AP + DNS spoofing、または Magisk module で /etc/hosts を編集。

クイックな Flutter TLS バイパス ワークフロー (Frida Codeshare + system CA)

ピン留めされた Flutter API を観察するだけなら、rooted/書き込み可能な AVD、システム信頼のプロキシ CA、そしてドロップインの Frida スクリプトを組み合わせる方が、libflutter.so をリバースエンジニアリングするより高速なことが多い:

  1. プロキシ CA をシステムストアにインストールする。 Install Burp Certificate に従って Burp の DER 証明書をハッシュ/リネームし、/system/etc/security/cacerts/ に配置する(書き込み可能な /system が必要)。

  2. 一致する frida-server バイナリを配置し root で実行する ことで 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. ホスト側のツールをインストールし、ターゲットパッケージを列挙する。
pip3 install frida-tools --break-system-packages
adb shell pm list packages -f | grep target
  1. BoringSSL の pin checks を無力化する Codeshare hook で Flutter アプリを spawn する。
frida -U -f com.example.target --codeshare TheDauntless/disable-flutter-tls-v1 --no-pause

The Codeshare script overrides the Flutter TLS verifier so every certificate (including Burp’s dynamically generated ones) is accepted, side-stepping public-key pin comparisons.

  1. プロキシ経由でトラフィックをルーティングする。 Configure the emulator Wi‑Fi proxy GUI or enforce it via adb shell settings put global http_proxy 10.0.2.2:8080; if direct routing fails, fall back to adb reverse tcp:8080 tcp:8080 or a host-only VPN.

  2. アプリがOSのプロキシ設定を無視する場合、Frida シムでソケットをリダイレクトする。 Tools like frida4burp hook dart:io/BoringSSL socket creation to force outbound TCP sessions to your proxy, even with hardcoded HttpClient.findProxyFromEnvironment or Wi‑Fi bypasses. Set the proxy host/port in the script and run it alongside the TLS bypass:

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

iOS 上でも Frida gadget または USB frida-server 経由で動作します;socket redirect と TLS bypass を組み合わせることで、Burp/mitmproxy に対するルーティングと証明書の受け入れの両方が復元されます。

OS レイヤーで CA が信頼され、Frida が Flutter の pinning logic を無効化し(必要なら socket redirection も)、Burp/mitmproxy は APK を再パッケージせずに API fuzzing(BOLA、token tampering など)に対する完全な可視性を取り戻します。

BoringSSL verification のオフセットベースのフック(シグネチャスキャンなし)

パターンベースのスクリプトがアーキテクチャ間(例: x86_64 と ARM)で失敗する場合、libflutter.so 内の絶対アドレスで直接 BoringSSL のチェーン検証器をフックします。ワークフロー:

  • APK から正しい ABI のライブラリを抽出: unzip -j app.apk "lib/*/libflutter.so" -d libs/ と、デバイスに合うものを選択(例: lib/x86_64/libflutter.so)。
  • Ghidra/IDA で解析して検証器を見つける:
  • ソース: BoringSSL ssl_x509.cc の関数 ssl_crypto_x509_session_verify_cert_chain(3 引数、戻り値は bool)。
  • Stripped ビルドでは、Search → For Strings → ssl_client → XREFs を使い、参照された各 FUN_... を開いて、3 つのポインタ風引数と boolean の戻り値を持つものを選びます。
  • ランタイムオフセットを計算: Ghidra に表示される関数アドレスから image base を引く(例: Ghidra は PIE Android ELF に対してしばしば 0x00100000 を表示します)。例: 0x02184644 - 0x00100000 = 0x02084644
  • ランタイムで base + offset にフックし、成功を強制する:
// 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);

注意

  • Signature scans は、opcode レイアウトが変わるため ARM では成功しても x86_64 では失敗することがあります; この offset メソッドは、RVA を再計算すればアーキテクチャに依存しません。
  • このバイパスは BoringSSL に任意の chain を受け入れさせ、Flutter 内の pins/CA trust に関係なく HTTPS MITM を可能にします。
  • デバッグ時に TLS ブロッキングを確認するためにトラフィックを強制ルーティングする場合、例えば:
iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination <Burp_IP>:<Burp_Port>

…上記の hook は依然として必要です。検証は libflutter.so の内部で行われ、Android’s system trust store では行われません。

参考資料

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする