Home ios Pentesting - SSL Pinning on Flutter
Post
Cancel

ios Pentesting - SSL Pinning on Flutter

  • 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)
  • 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 under Flutter.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
  • 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/
This post is licensed under CC BY 4.0 by the author.