Flutter

Reading time: 5 minutes

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

FlutterはGoogleのクロスプラットフォームUIツールキットで、開発者が単一のDartコードベースを書き、Engine(ネイティブC/C++)がAndroidおよびiOS用のプラットフォーム固有の機械コードに変換します。エンジンはDart VMBoringSSL、Skiaなどをバンドルし、共有ライブラリlibflutter.so(Android)またはFlutter.framework(iOS)として出荷されます。すべての実際のネットワーキング(DNS、ソケット、TLS)はこのライブラリ内で行われ、通常のJava/Kotlin Swift/Obj-Cレイヤーではありません。この分離された設計が、通常のJavaレベルのFridaフックがFlutterアプリで失敗する理由です。

FlutterでのHTTPSトラフィックの傍受

これはこのブログ投稿の要約です。

FlutterでのHTTPS傍受が難しい理由

  • SSL/TLS検証はBoringSSLの2層下に存在するため、JavaのSSLピンニングバイパスでは触れません。
  • BoringSSLはlibflutter.so内に独自の CAストアを使用しているため、Burp/ZAP CAをAndroidのシステムストアにインポートしても何も変わりません。
  • libflutter.so内のシンボルはストリップされており、マングルされています。これにより、動的ツールから証明書検証関数が隠されます。

正確なFlutterスタックのフィンガープリンティング

バージョンを知ることで、正しいバイナリを再構築またはパターンマッチできます。

StepCommand / FileOutcome
スナップショットハッシュを取得bash\npython3 get_snapshot_hash.py libapp.so\nadb4292f3ec25…
ハッシュを→エンジンにマップenginehashリストをreFlutterでFlutter 3 · 7 · 12 + engine commit 1a65d409…
依存コミットをプルそのエンジンコミットのDEPSファイルdart_revision → Dart v2 · 19 · 6
dart_boringssl_rev → BoringSSL 87f316d7…

ここでget_snapshot_hash.pyを見つける

ターゲット: ssl_crypto_x509_session_verify_cert_chain()

  • BoringSSL内のssl_x509.ccにあります
  • boolを返します – 単一のtrueで全体の証明書チェーンチェックをバイパスできます。
  • 同じ関数はすべてのCPUアーキテクチャに存在し、オペコードのみが異なります。

オプションA – reFlutterを使用したバイナリパッチ

  1. アプリのFlutterバージョンに対して正確なエンジンとDartソースをクローンします。
  2. 2つのホットスポットを正規表現パッチします:
  • ssl_x509.ccで、return 1;を強制します。
  • (オプション)socket_android.ccで、プロキシをハードコーディングします("10.0.2.2:8080")。
  1. libflutter.soを再コンパイルし、APK/IPAに戻し、署名してインストールします。
  2. 一般的なバージョンのための事前パッチビルドがreFlutterのGitHubリリースに出荷され、ビルド時間を数時間節約します。

オプションB – Fridaを使用したライブフック(「ハードコア」パス)

シンボルがストリップされているため、読み込まれたモジュールの最初のバイトをパターンスキャンし、動的に戻り値を変更します。

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

実行する:

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

ポーティングのヒント

  • arm64-v8a または armv7 の場合、Ghidraから関数の最初の約32バイトを取得し、スペース区切りの16進数文字列に変換して sig を置き換えます。
  • Flutterのリリースごとに1つのパターンを保持し、迅速な再利用のためにチートシートに保存します。

プロキシを通じてトラフィックを強制する

Flutter自体は デバイスのプロキシ設定を無視します。最も簡単なオプション:

  • Android Studioエミュレーター: 設定 ▶ プロキシ → 手動。
  • 物理デバイス: 悪意のあるWi-Fi AP + DNSスプーフィング、またはMagiskモジュールで /etc/hosts を編集。

参考文献