During one of our recent thick client application penetration tests, Sanjay encountered a scenario where the application was built on top of a Flutter framework and had an SSL pinning check in one of the embedded libraries. Due to this check, the application provided an SSL pinning error when it was configured using Burp.
To share our experience and for the purpose of this blog, we will be using 'thickclient.example.com' as a backend API URL for Mac OSX thick client application.
TL;DR
Bypass SSL Pinning implementation for Flutter based Mac OSX thick client application by hooking Frida script in Mac OSX thick client application.
Problem Statement
The challenge was to pentest or modify the network traffic generated by Mac OSX thick client application in Burp Proxy, as the application provided an SSL pinning error when configured using Burp.
Problem Analysis
During the process of Mac OSX thick client application pentest, to capture the application’s HTTP traffic, we used well-known tools like Burp Suite, Charles Proxy, and Proxyman, configured using well-known proxy configuration techniques. It was observed that none of the tools and techniques could capture the Mac OSX thick client application’s traffic.
Using Wireshark to analyze the thick client application network traffic, we observed that the application communicated over TCP and TLSv1.2, which meant encrypted traffic in Wireshark. When we further analysed the traffic using the 'follow tcp stream' feature of Wireshark, domain name 'thickclient.example.com' was found.
Then we tried to run the application using command prompt and observed the logging of the application like 'flutter: $STRING$', and based on analysis we concluded that the application was built in Flutter.
Based on the article, we observed that we can set the environment variable to forward the traffic of Flutter based Mac OSX thick client applications.
export HTTP_PROXY=localhost:8080 export HTTPS_PROXY=localhost:8080
But we also observed that on setting the environment variable we got the SSL Pinning error for 'thickclient.example.com' as shown below:
In order to list the modules used by the Mac OSX thick client application, we used the following Frida script.
We hooked the Frida script inside the thick client application and observed that the application loaded the 'FlutterMacOS' library inside it. Android and iOS applications might be using ‘libflutter.so’ for Flutter based applications.
As mentioned earlier in the blog, the application validates the 'Certificate Verification' at 'handshake.cc: line:354' as shown in figure, when configured using any proxy.
We did a quick google search for 'handshake.cc: line:354' keyword and found 'handshake.cc' file inside 'boringSSL' source code on Github. We then analysed the open source boringSSL codebase to check what was inside 'handshake.cc'. At line 354, it was observed that the 'session_verify_cert_chain' function was called from the 'ssl_verify_peer_cert' function, which validates SSL Pinning and returns the 'enum ssl_verify_result_t'.
Furthermore, we analyzed this blog based on SSL Pinning bypass in Flutter based applications for Android and opened up the 'FlutterMacOS' in 'Ghidra' reverse engineering tool.
We captured the first 27 bytes of the function 'ssl_verify_peer_cert'.
Next we ran the Binwalk tool to confirm the first 27 bytes of the function and found that it gave a single entry for the function 'ssl_verify_peer_cert' function.
Sometimes it may so happen that multiple functions use the same 27 bytes sequence, in that case, we have to add more sequences of bytes of the actual function to hook only a particular function in the result. For example, let's hook the function with first 24 bytes sequence, so when Binwalk is run against first 24 bytes, it results in more than 25 instances as shown in figure below, and when we hook Frida using first 24 bytes sequence, it will hook all the functions which might cause the application to crash or not work as intended.
For such scenarios, we have to increase the sequence of bytes to get the exact function as shown in above steps:
We used the Frida script from the article to hook it in the thick client application.
If the function is hooked it will log the following message:
Disabling SS validation Retval: 0xADDRESS
We ran the application and hooked the Frida script and performed login activity against the thick client application.
Boom….
The function was hooked by the Frida script and the return value was replaced from '0x2' to '0x0'. It means that when the proxy is set and the function is returned, it will return 'ssl_verify_retry' -> 0x02 and with Frida hooking it will return 'ssl_verify_ok' -> 0x0.
Now, we could finally capture the traffic of Flutter based Mac OSX thick client applications in proxy.
Reference:
- https://blog.nviso.eu/2019/08/13/intercepting-traffic-from-android-flutter-applications/
- https://github.com/poxyran/misc/blob/master/frida-enumerate-modules.py
- https://github.com/google/boringssl/blob/master/ssl/handshake.cc
- https://api.flutter.dev/flutter/dart-io/HttpClient/findProxyFromEnvironment.html
- https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#ssl_verify_result_t
- https://portswigger.net/burp/documentation/desktop/tools/proxy/options/invisible
- https://www.charlesproxy.com/documentation/