| name | flutter-ssl-bypass |
| description | Bypass SSL/TLS pinning in Flutter apps to intercept HTTPS traffic with Burp or mitmproxy. Use this skill whenever you need to intercept Flutter app traffic, bypass certificate pinning on Android/iOS, or analyze Flutter network requests. Flutter apps use BoringSSL inside libflutter.so which ignores standard Android SSL pinning bypasses - this skill covers Frida hooking, binary patching, and offset-based techniques to force certificate acceptance. |
Flutter SSL/TLS Bypass
Flutter apps run networking code inside libflutter.so (Android) or Flutter.framework (iOS), which bundles BoringSSL. This means:
- Java/Kotlin SSL pinning bypasses don't work - verification happens in native code
- System CA store is ignored - BoringSSL uses its own CA store
- Symbols are stripped - you can't hook by function name
This skill covers three approaches to bypass Flutter TLS verification:
Quick Decision Tree
| Situation | Recommended Approach |
|---|
| Rooted device, need fast bypass | Frida Codeshare + system CA |
| Can't use Codeshare, have Ghidra | Offset-based hooking |
| Can rebuild the app | Binary patching with reFlutter |
| Multiple Flutter versions | Pattern-based Frida hooking |
Method 1: Frida Codeshare (Fastest)
When you have a rooted device or writable AVD, this is the quickest path:
Step 1: Install Proxy CA in System Store
adb push burp.der /system/etc/security/cacerts/
adb shell "chmod 644 /system/etc/security/cacerts/burp.der"
See install-burp-certificate.md for full instructions on hashing and renaming.
Step 2: Deploy Frida Server
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 &'"
Step 3: Spawn App with TLS Bypass
frida -U -f com.example.target --codeshare TheDauntless/disable-flutter-tls-v1 --no-pause
This Codeshare script overrides the Flutter TLS verifier to accept all certificates.
Step 4: Route Traffic Through Proxy
adb shell settings put global http_proxy 10.0.2.2:8080
adb reverse tcp:8080 tcp:8080
Step 5: Force Socket Redirection (if needed)
If the app ignores proxy settings:
frida -U -f com.example.target --no-pause \
--codeshare TheDauntless/disable-flutter-tls-v1 \
-l scripts/frida4burp.js
Method 2: Offset-Based Hooking (Architecture-Agnostic)
When pattern scanning fails across architectures, hook by absolute offset:
Step 1: Extract libflutter.so
unzip -j app.apk "lib/*/libflutter.so" -d libs/
Step 2: Analyze in Ghidra
- Open
libflutter.so in Ghidra
- Search → For Strings →
ssl_client
- Go to XREFs and examine each
FUN_... reference
- Find the function with:
- 3 pointer-like arguments
- Boolean return type
- Located near BoringSSL code
This is ssl_crypto_x509_session_verify_cert_chain() from ssl_x509.cc.
Step 3: Calculate Runtime Offset
Step 4: Hook at Runtime
Use scripts/offset-hook.js:
frida -U -f com.target.app -l scripts/offset-hook.js --no-pause
Method 3: Pattern-Based Hooking
For known Flutter versions, use opcode pattern matching:
Step 1: Get the Pattern
For x86-64, the first 16 bytes of ssl_crypto_x509_session_verify_cert_chain:
55 41 57 41 56 41 55 41 54 53 48 83 EC 38 C6 02
For ARM64/ARMv7, extract from Ghidra:
- Open
libflutter.so in Ghidra
- Navigate to the verifier function
- Copy first ~32 bytes as space-separated hex
Step 2: Run Pattern Hook
Use scripts/pattern-hook.js:
frida -U -f com.example.app -l scripts/pattern-hook.js
Method 4: Binary Patching with reFlutter
For permanent bypass without runtime hooking:
Step 1: Identify Flutter Version
unzip app.apk lib/x86_64/libapp.so
python3 scripts/get_snapshot_hash.py libapp.so
Step 2: Map to Engine Version
- Search the hash in reFlutter enginehash list
- Note the Flutter version and engine commit
- Pull DEPS file to find BoringSSL revision
Step 3: Patch and Rebuild
git clone https://github.com/Impact-I/reFlutter
cd reFlutter
Step 4: Replace in APK
apktool d app.apk -o app-decompiled
apktool b app-decompiled -o app-patched.apk
apksigner sign --ks mykey.jks app-patched.apk
Forcing Proxy Traffic
Flutter ignores device proxy settings. Options:
| Platform | Method |
|---|
| Android Emulator | Settings → Proxy → Manual |
| Physical Device | Evil Wi-Fi AP + DNS spoofing |
| Rooted Device | Magisk module editing /etc/hosts |
| Any | Frida socket redirection (see Method 1, Step 5) |
Verification
After applying any bypass:
- Start Burp/mitmproxy on port 8080
- Launch the app with Frida attached
- Watch for traffic in your proxy
- Test certificate acceptance - Burp's dynamically generated certs should be accepted
If you see SSL handshake failed or no traffic:
- Verify CA is in system store (not user store)
- Check Frida is attached and hook is active
- Confirm proxy routing is working
- Try offset-based method if pattern scanning fails
Troubleshooting
| Problem | Solution |
|---|
| Hook not triggering | Verify libflutter.so is loaded: frida-ps -Ua |
| Wrong architecture | Match Frida server and libflutter.so arch (x86_64 vs arm64) |
| Pattern not found | Use offset-based method instead |
| Traffic not routing | Use frida4burp.js for socket redirection |
| App crashes on hook | Ensure return type matches (bool = int in C) |
References