Hacktricks-skills flutter-ssl-bypass
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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/mobile-pentesting/android-app-pentesting/flutter/SKILL.MDFlutter 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
# Get Burp CA certificate (DER format) # Hash it and push to 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
# Emulator adb shell settings put global http_proxy 10.0.2.2:8080 # Or use reverse tunnel 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/ # Pick the one matching your device architecture # e.g., libs/lib/x86_64/libflutter.so or libs/lib/arm64-v8a/libflutter.so
Step 2: Analyze in Ghidra
- Open
in Ghidralibflutter.so - Search → For Strings →
ssl_client - Go to XREFs and examine each
referenceFUN_... - 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
# Example: Ghidra shows 0x02184644, image base is 0x00100000 # Offset = 0x02184644 - 0x00100000 = 0x02084644
Step 4: Hook at Runtime
Use
scripts/offset-hook.js:
# Edit the script with your calculated offset # Then run: 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
in Ghidralibflutter.so - Navigate to the verifier function
- Copy first ~32 bytes as space-separated hex
Step 2: Run Pattern Hook
Use
scripts/pattern-hook.js:
# Edit with your architecture's pattern 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
# Extract libapp.so from APK unzip app.apk lib/x86_64/libapp.so # Get snapshot hash python3 scripts/get_snapshot_hash.py libapp.so # Output: adb4292f3ec25...
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 # Follow build instructions for your Flutter version # Patch ssl_x509.cc to force return 1 # Rebuild libflutter.so
Step 4: Replace in APK
# Extract APK apktool d app.apk -o app-decompiled # Replace libflutter.so in appropriate arch folder # Rebuild and sign 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 |
| 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: |
| 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 for socket redirection |
| App crashes on hook | Ensure return type matches (bool = int in C) |