- Flutter application is proxy unware and we cannot redirect the traffic through WIFI proxy. In android, we can do it by ProxyDroid but, in iOS we need to do it through VPN.
1 2 3 4
sudo wget https://git.io/vpn -O openvpn-install.sh sudo sed -i "$(($(grep -ni "debian is too old" openvpn-install.sh | cut -d : -f 1)+1))d" ./openvpn-install.sh sudo chmod +x openvpn-install.sh sudo ./openvpn-install.sh
- Enter below details after running the script
- Which IPv4 address should be used?
- Use your PC IP.
- Public IPv4 address / hostname []:
- Use your PC IP.
- Protocol
- 1
- Port
- 1194
- DNS Server
- 1
- Name [client]:
- name_any (Example: newvpn)
- Which IPv4 address should be used?
The openvpnn file is created under /root/ directory. In this case, /root/newvpn.ovpn.
- Install OpenVPN application on the iOS device.
- Host the newly created VPN file from PC.
cd /root/
python3 -m http.server 1337
Download the VPN file and import it to the installed OpenVPN application in iOS.
- Start the openvpn service on PC.
sudo service openvpn start
- Route the traffic to burp in PC.
1 2 3
sudo iptables -t nat -A PREROUTING -i tun0 -p tcp --dport 80 -j REDIRECT --to-port 8080 sudo iptables -t nat -A PREROUTING -i tun0 -p tcp --dport 443 -j REDIRECT --to-port 8080 sudo iptables -t nat -A POSTROUTING -s 192.168.101.76/24 -o eth0 -j MASQUERADE
- Here, replace the IP 192.168.101.76 by the iOS device IP.
- Open the burp suite and listen on the address generated by OpenVPN - tun0
- Also, click on Support invisible proxying (enable only if needed)
Now we are able to forward the traffic from iOS device to the PC, but we need to bypass the SSL pinning as well.
- Grab the Bundle.
- Use Frida-iOS dump to Grab the iPA bundle from iOS device.
- Rename the .IPA file to .ZIP and extract the files and folders.
- There is a Exectutable file called
Flutter
underFlutter.framework
directory - Example, if the app name is TouchMe.app then the path for the executable file is
/TouchMe.app/Frameworks/Flutter.framework/Flutter
- Verify if the file
Flutter
contains x509.cc SSL verification.strings Flutter | grep -i 'x509.cc'
- Little bit of reverse engineering.
- Install Ghidra and Open the file Flutter from the bundle.
- Click on Search -> scalars -> Enter 0x186 on the filter.
- More info here
- If we do not find the 0x186 on Scalar, this method might not work on bypassing SSL pinning.
- Alternative method (Works most of the time)
- Flutter engine has been changed and the previous method might not be sufficient to bypass the pinning on iOS app. The application nowadays uses Dio class with httpClientAdaptor in order to connect to the URL.
- Use below script to bypass the SSL if the application uses DIO package in flutter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
function bypass_SecTrustEvaluates() { // Bypass SecTrustEvaluateWithError var SecTrustEvaluateWithErrorHandle = Module.findExportByName('Security', 'SecTrustEvaluateWithError'); if (SecTrustEvaluateWithErrorHandle) { var SecTrustEvaluateWithError = new NativeFunction(SecTrustEvaluateWithErrorHandle, 'int', ['pointer', 'pointer']); // Hooking SecTrustEvaluateWithError Interceptor.replace(SecTrustEvaluateWithErrorHandle, new NativeCallback(function(trust, error) { console.log('[!] Hooking SecTrustEvaluateWithError()'); SecTrustEvaluateWithError(trust, NULL); if (error != 0) { Memory.writeU8(error, 0); } return 1; }, 'int', ['pointer', 'pointer'])); } // Bypass SecTrustGetTrustResult var SecTrustGetTrustResultHandle = Module.findExportByName("Security", "SecTrustGetTrustResult"); if (SecTrustGetTrustResultHandle) { // Hooking SecTrustGetTrustResult Interceptor.replace(SecTrustGetTrustResultHandle, new NativeCallback(function(trust, result) { console.log("[!] Hooking SecTrustGetTrustResult"); // Change the result to kSecTrustResultProceed Memory.writeU8(result, 1); // Return errSecSuccess return 0; }, "int", ["pointer", "pointer"])); } // Bypass SecTrustEveluate var SecTrustEvaluateHandle = Module.findExportByName("Security", "SecTrustEvaluate"); if (SecTrustEvaluateHandle) { var SecTrustEvaluate = new NativeFunction(SecTrustEvaluateHandle, "int", ["pointer", "pointer"]); // Hooking SecTrustEvaluate Interceptor.replace(SecTrustEvaluateHandle, new NativeCallback(function(trust, result) { console.log("[!] Hooking SecTrustEvaluate"); var osstatus = SecTrustEvaluate(trust, result); // Change the result to kSecTrustResultProceed Memory.writeU8(result, 1); // Return errSecSuccess return 0; }, "int", ["pointer", "pointer"])); } } // Main if (ObjC.available) { bypass_SecTrustEvaluates(); } else { send("error: Objective-C Runtime is not available!"); }
- Frida
- View the package name:
frida-ps -Uai | grep 'appnname'
- Use the above script:
frida -U -f package-name -l aboveScript.js --no-pause
- View the package name:
The HTTPS traffic now can be intercepted on the Burp Suite.
- References
- https://blog.nviso.eu/2020/06/12/intercepting-flutter-traffic-on-ios/
- https://bhattsameer.github.io/2021/06/23/Intercepting-flutter-iOS-application.html
- https://mcaiden.com/2022/06/04/bypassing-certificate-pinning-on-a-flutter-based-ios-app/
ios Pentesting - SSL Pinning on Flutter
This post is licensed under CC BY 4.0 by the author.