f3rb123/kill_flutter

GitHub: f3rb123/kill_flutter

一款跨版本的 Flutter SSL Pinning 绕过工具,通过动态分析 Flutter 引擎二进制文件中的 BoringSSL 证书校验函数并生成即用型 Frida 脚本,实现对任意版本 Flutter 应用流量的拦截。

Stars: 1 | Forks: 0

# 干掉 Fl!utter 🔪 ![K!ll Fl!utter](https://static.pigsec.cn/wp-content/uploads/repos/cas/cb/cb8c65dc1f27ffe92ce2976312876a7666b3c46d434efda578c2a08eeaaee443.png) ## 背景 几个月前,在一次常规的 Flutter 应用渗透测试中,常见的 SSL pinning 绕过方法全都失效了——常用的 Frida 脚本和 reFlutter,都没能将流量导入 Burp。这让我陷入了对 Flutter *为何*如此难以拦截的深度探究,而这款工具就是探究的成果。 ## 为什么 Flutter 与众不同 Flutter 不使用手机常规的网络栈。它自带了编译进原生文件的网络引擎(BoringSSL)——在 Android 上是 `libflutter.so`,在 iOS 上是 `Flutter` 框架。所有的证书校验都在这个编译后的文件内部进行。 这也是为什么像 **Objection** 和 **SSL Kill Switch** 这样的操作系统级绕过工具不起作用的原因——它们 hook 的是系统信任 API,而 Flutter 从不调用这些 API。它直接在自己的引擎内部走向 BoringSSL。 所以在面对 Flutter 时,你只剩下两种真正的选择——而在现代版本中,这两种方法都失效了。 ## 为什么常规工具会失效 ### 公开的 Frida 脚本 这些脚本在**硬编码偏移量**处 hook 证书校验函数,该偏移量是通过逆向工程某个特定版本的 Flutter 引擎得出的。问题在于:每个版本中的偏移量都是不同的。Flutter 不断发布新版本,每个引擎版本的编译方式也不同,因此该函数每次都会移动到一个新的地址。为旧版本编写的脚本会指向错误的位置,匹配不到任何内容,hook 永远无法生效。脚本并没有失效——是它底层的二进制文件发生了移动。 ### reFlutter 很长一段时间里,这都是 Flutter 的首选工具,并且它确实管用。它从应用中读取快照哈希,将其与已知 Flutter 引擎版本的表格进行匹配,然后重新编译一个打过补丁的引擎来替换。但是那个表格必须针对每个 Flutter 版本手动更新,如今已经落后了——在较新的版本中,哈希值无法被识别,它会报告该引擎不受支持。 ### 共同点 这两个工具都绑定到了特定的 Flutter 版本——一个是通过硬编码偏移量,另一个是通过查找表。Flutter 的发布速度超出了它们的更新速度,因此两者都会随着时间推移而衰退,并在当前的应用上失效。 ## 更深层的问题 引擎二进制文件已被剥离——没有函数名,也没有标签。用手工方式查找证书校验函数意味着要在 Ghidra 或 IDA 中耗费数小时,而且由于偏移量在每个版本中都会改变,你必须为每个新版本重新进行这项工作。 ## K!ll Fl!utter 的工作原理有何不同 它不使用硬编码偏移量或版本表,而是利用在每个 Flutter 版本中保持不变的属性,**在每一个二进制文件中重新查找**该函数: 1. **字符串锚点** — BoringSSL 的校验函数总是引用两个固定的字符串:`ssl_client` 和 `ssl_server`。这些字符串内置在 BoringSSL 自己的源码中,存在于所有编译过的 Flutter 二进制文件中。 2. **ADRP+ADD 指令扫描** — ARM64 总是使用 `ADRP+ADD` 指令对来加载字符串地址。这是架构层面的常量,并非 Flutter 特有的模式。扫描指向锚点字符串的指令对即可定位函数主体。 3. **序言回溯** — ARM64 函数总是以栈设置指令(`STP x29,x30` 或 `SUB sp`)开始。从锚点向后回溯到该指令,就能得出准确的函数起始位置。 由此,它可以计算出该特定二进制文件中证书校验函数的准确**偏移量**。因为它每次都会重新计算偏移量,所以 Frida hook 能够精准作用于任何版本——**无需手动逆向工程,无需 Ghidra,无需版本表,也无需不断进行更新。** ``` APK / IPA └── Extract Flutter engine binary (libflutter.so / Flutter framework) └── Find ssl_client + ssl_server string anchors └── Scan ADRP+ADD instruction pairs referencing both └── Walk back to ARM64 function prologue └── Offset calculated → Frida script generated └── iptables redirect → traffic hits Burp ``` ## 流程 1. 将其指向一个 APK 或 IPA 2. 它会提取 Flutter 引擎文件 3. 它会找到证书校验函数并计算其偏移量 4. 它会生成一个即用型的 Frida 脚本,强制使校验通过 5. 它会打印出将流量路由到你的代理的确切命令(Flutter 会忽略代理设置,因此它使用内核级的重定向) 将其指向某个应用,就能获得一个可用的 Frida 脚本和可直接复制粘贴的命令。 ## 可以绕过哪些 Pinning ✅ 默认的 Flutter `HttpClient` (dart:io) 证书验证 ✅ `dio` 包的 SSL pinning ✅ 基于 Flutter HTTP 栈构建的自定义证书验证器 ✅ 任何最终会调用 `ssl_crypto_x509_session_verify_cert_chain` 的 pinning ❌ mTLS / 客户端证书 pinning(服务器要求提供客户端证书) ❌ Flutter 之外的 Android/iOS 原生证书 pinning ❌ Root / 越狱检测(属于另一个独立问题) ## 环境要求 | 要求 | 说明 | |---|---| | Python 3 | 任何较新的版本 | | `frida-tools` | `pip install frida-tools` | | `aapt` | Android SDK build tools(仅限 Android,用于包名检测) | | 已 Root 的 Android **或** 已越狱的 iOS | Frida + iptables 必需 | | Burp Suite | 社区版或专业版 | ## 安装说明 ``` git clone https://github.com/f3rb/kill_flutter cd kill_flutter pip install frida-tools ``` ## 使用方法 ``` # 帮助 python3 kill_flutter.py -h # Android APK python3 kill_flutter.py app.apk -i 192.168.1.10 -p 8080 # iOS IPA python3 kill_flutter.py app.ipa -i 192.168.1.10 -p 8080 --device-ip 192.168.1.50 # 自定义输出目录 python3 kill_flutter.py app.apk -i 192.168.1.10 -o /tmp/pentest # 强制指定 platform(如果扩展名不明确) python3 kill_flutter.py app.apk --platform android -i 192.168.1.10 ``` ## 选项 | 参数 | 说明 | 默认值 | |---|---|---| | `app` | APK 或 IPA 的路径 | 必填 | | `-i, --ip` | 你的机器 IP 地址 | `` | | `-p, --port` | Burp Suite 监听端口 | `8080` | | `-o, --output` | 生成文件的输出目录 | 应用所在目录 | | `--platform` | 强制指定平台:`android` 或 `ios` | 自动检测 | | `--device-ip` | 用于 SSH iptables 的 iOS 设备 IP | `` | | `-h, --help` | 显示帮助信息 | — | ## 输出 该工具运行一次即可生成所需的所有内容: - `flutter_bypass.js` — 内置偏移量的即用型 Frida 脚本 - 可复制粘贴的 iptables 命令(Android 通过 adb / iOS 通过 SSH) - 自动填充了包名的可复制粘贴 Frida 启动命令 ``` [*] Platform : ANDROID [+] Package : com.example.flutterapp [+] ssl_client @ ['0x1a1d75'] [+] ssl_server @ ['0x1ab471'] [*] Scanning ADRP+ADD refs... (may take a moment) [+] SSL verify offset: 0x740cc8 [+] Frida script saved: /path/to/flutter_bypass.js [3] Launch Frida: frida -U -f com.example.flutterapp -l "/path/to/flutter_bypass.js" ``` ## Burp Suite 设置 1. Proxy → Listeners → 在 `8080` 端口添加监听器 2. Bind address → **All interfaces** (`0.0.0.0`) 3. Request handling → ✅ **Support invisible proxying** 4. Intercept → **Off** ## 还原 **Android:** ``` adb shell su -c "iptables -t nat -D OUTPUT -p tcp --dport 443 -j DNAT --to-destination :8080" adb shell su -c "iptables -t nat -D OUTPUT -p tcp --dport 80 -j DNAT --to-destination :8080" # 或者直接: adb reboot ``` **iOS:** ``` ssh root@ "iptables -t nat -D OUTPUT -p tcp --dport 443 -j DNAT --to-destination :8080" ssh root@ "iptables -t nat -D OUTPUT -p tcp --dport 80 -j DNAT --to-destination :8080" # 或者直接重启设备 ``` ## 它是如何找到函数的 — 技术细节 Flutter 的引擎二进制文件已被完全剥离。函数 `ssl_crypto_x509_session_verify_cert_chain` 无法通过名称找到,因此只能通过行为来定位: **字符串锚点** — BoringSSL 源码包含: ``` const char *peer = SSL_is_server(ssl) ? "ssl_client" : "ssl_server"; ``` 这些字符串是该函数独有的,并且存在于每个版本中。通过字节扫描可以找到它们的文件偏移量。 **段解析** — ARM64 指令编码的是虚拟地址,而不是文件偏移量。该工具会解析 ELF(Android)或 Mach-O(iOS)段头,以构建文件偏移量与虚拟地址的映射关系,从而确保指令扫描的正确性。 **ADRP+ADD 扫描** — 它会扫描可执行段中立即数与每个字符串虚拟地址的低 12 位相匹配的 `ADD` 指令,然后验证前一个 `ADRP` 是否指向了正确的 4 KB 页面。这样就能定位到加载这两个字符串的代码。 **序言回溯** — 从同址引用处开始,它会向后回溯到第一条函数序言指令。这就是校验函数的起始位置——也就是内置到 Frida 脚本中的偏移量。 **Hook** — 在运行时,ASLR 会对库的基地址进行随机化处理,但偏移量是固定的。`module.base + offset` 始终能解析到该函数: ``` var addr = m.base.add(offset); Interceptor.attach(addr, { onLeave: function(retval) { retval.replace(0x1); // force verification success } }); ``` **流量重定向** — Flutter 直接发起 TCP 连接,忽略了系统代理,因此内核级的 iptables DNAT 会将所有发往 443/80 的出站流量重定向到 Burp,而不管应用自身的行为如何。 ## 参考资料 - [PT Swarm — Fork Bomb for Flutter (reFlutter 内部机制)](https://swarm.ptsecurity.com/fork-bomb-for-flutter/) - [SensePost — 使用 Frida 拦截 Flutter 中的 HTTPS](https://sensepost.com/blog/2025/intercepting-https-communication-in-flutter-going-full-hardcore-mode-with-frida/) - [NVISO — 拦截 Flutter 流量](https://blog.nviso.eu/2022/08/18/intercept-flutter-traffic-on-ios-and-android-http-https-dio-pinning/) - [reFlutter](https://github.com/ptswarm/reFlutter) - [BoringSSL 源码 — ssl_x509.cc](https://github.com/google/boringssl/blob/master/ssl/ssl_x509.cc) ## 免责声明 本工具仅供**授权的安全测试使用**。请仅在您拥有明确书面测试许可的应用上使用。作者不对因使用本工具而造成的任何滥用或损坏负责。 ## 作者 **f3rb** — 进攻性安全 | 移动端渗透测试 | 工具开发
标签:Docker支持, Flutter, Frida, SSL Pinning绕过, StruQ, 云资产清单, 目录枚举, 移动安全, 逆向工具, 逆向工程