In a previous article we learned how to perform a MitM attack on a mobile app that doesn’t employ certificate pinning as a mechanism of preventing such attacks.
Today I will show how to use the Frida instrumentation framework to hook into the mobile app at runtime and instrument the code in order to perform a successful MitM attack even when the mobile app has implemented certificate pinning.
Previously we used the ShipFast app with the build variant that doesn’t have certificate pinning enabled, but in this approach we will use the build variant with certificate pinning enabled via the network security config file. Therefore the app will not trust user provided certificates, or certificates in the Android OS (operating system) trusted system store.
To distinguish it from the previous build variant the user interface variant for certificate pinning variant uses a different color, but the user experience is the same. Since the APK is not the same as in the previous article you will need to follow the instructions to download the APK for the certificate pinning variant.
The setup for the MitM attack is the same, but has some additional steps to install and setup Frida, in order to bypass certificate pinning.
The reasons to bypass certificate pinning are not different from the ones that we talked about in the previous article to carry out a MitM attack. With this in mind let’s review one more time some of the possible reasons to carry out such an attack.
On one side you may have legitimate users wanting to get around limitations imposed by the mobile app’s user interface to access certain services, where those services are available via the API. Just one of many potential examples would be where the legitimate user of a mobile app may want to gamify or have access to features/resources not available within his/her current subscription plan, or because they want to collect/use more reward points or discount vouchers then they are allowed to or entitled to.
On the other side we may have attackers or security researchers wanting to intercept the communications between your mobile app and your API server in order to collect enough information to automate attacks against it, or just to modify or redirect your data on the fly.
To perform a MitM attack in this context, where mobile apps use certificate pinning, is not as straightforward as the approach we learned in the previous article; for an effective attack in this situation, a way to bypass certificate pinning needs to be found.
Using Frida to bypass certificate pinning is achievable by anyone who is tech savvy and is used to following tutorials to customize their IT gadgets, such as mobile devices, computers or others. The task is made even easier by using any of the numerous Frida code snippets available at the Frida CodeShare website, enabling the certificate pinning bypass without the need for any coding skills.
If you browse the Frida code snippets, the first and third result at today's date (3rd May 2021) are for bypassing certificate pinning:
Bypassing certificate pinning seems to be the most popular code snippet type, and this comes as no surprise. A lot of mobile apps nowadays are using certificate pinning to protect the communication channel between the mobile app and the API server in order to keep the prying eyes of attackers and ‘over-enthusiastic’ users at bay. However, luckily for them and unfortunately for us, it is possible to get around certificate pinning.
The approach we are about to see will work out of the box for mobile apps using the network security config file to implement certificate pinning.
For mobile apps implementing certificate pinning by other means and/or using other defense mechanisms, additional customizations to this approach will be necessary, with varying degrees of difficulty.
If you have already followed the MitM attack from the previous article the only new requirement is the Frida setup, you can jump to steps 4 and 5 in the section below entitled Setup Required Tools. Otherwise, just keep on reading.
This tutorial will be step by step, and we will assume that you will be following it along on a Linux based computer and that you already have Android Studio installed and configured. This specific tutorial has been done on an Ubuntu 20.04 desktop computer, therefore if you are running in another platform you can try to use an Ubuntu 20.04 VM to follow along or adapt the steps to your current platform. Other linux distributions will probably work without any issues with this tutorial too, but haven't been tested.
To prepare your system to follow along this tutorial you need to follow this Github gist for the following steps:
Now that we have finished the setup of all requirements to perform the MitM attack with Frida we can start with the fun stuff.
To show how to bypass certificate pinning we will use the ShipFast mobile app release flavor for certificate pinning, indicated by the different color in the screenshots from the ShipFast app used in the previous article, and the need for you to also follow the installation steps. The ShipFast mobile app is part of this series of articles on practical API security for mobile apps, and can be found on this Github repo.
First we will use the ShipFast app in the emulator as a regular user. This means we will not attempt to do any type of attack on it. The goal is just to show how the mobile works in normal circumstances.
Next we will run ShipFast in an emulator which has been modified to include the mitmproxy certificate in its system trusted store and we will observe certificate pinning protecting the request to the API backend from being intercepted by the MitM attack against the ShipFast mobile app.
Finally, we will use the Frida instrumentation framework to hook into the code at runtime to always trust in any pins extracted from the certificate provided during the TLS handshake which the app does prior to establishing an https connection.
From following the previously recommend steps for the emulator setup with Android 29 you should already have an instance of the emulator running, and sitting on this screen:
Now proceed to the next section to install the certificate pinning version of the ShipFast mobile app.
First, download the ShipFast mobile app with:
curl -LO https://github.com/approov/shipfast-api-protection/releases/download/2.2.0/app-certificate_pinning-release.apk
Next, install it on the emulator:
adb install app-certificate_pinning-release.apk
Then, launch the app via adb with:
adb shell am start -n com.criticalblue.shipfast.certificate_pinning/com.criticalblue.shipfast.LoginActivity
Once the the mobile app is launched you should see this screen:
Now login with Auth0 by using any of the login methods:
After the login steps are completed successfully you should see the following:
Authorize the app to access your device location, and then you should be presented with this screen:
Now click on the I’m available toggle in the bottom right corner, and you should be able to proceed to the next screen:
You can continue to interact with the ShipFast mobile app and everything should just work without any issues, and the final screen should be similar to this one:
Next we will launch a MitM attack to see if the certificate pinning implementation is working as expected.
We say try because you will not succeed in this first attempt. The goal here is to show that the current certificate pinning implementation is working correctly.
From following the setup instructions for mitmproxy you should already have an terminal open with the mitmproxy:
The proxy is listening on port 8080 for the IP address of your WiFi network.
Close the current open emulator and start it again, but this time in writable mode and with a proxy set to your WiFi IP address (replace 192.168.0.08 with the same IP you used to start mitmproxy) on port `8080`:
emulator -avd pixel-android-api-29 -writable-system -http-proxy http://192.168.0.08:8080 &> /dev/null &
After the device have completed to boot you can proceed to the next step.
The ShipFast mobile app has certificate pinning enabled via the network security config file to protect prying eyes from intercepting requests to its API backend.
First, we need to stop the current running instance:
adb shell am force-stop com.criticalblue.shipfast.certificate_pinning
Now, launch the ShipFast app again via adb with:
adb shell am start -n com.criticalblue.shipfast.certificate_pinning/com.criticalblue.shipfast.LoginActivity
Now, login with Auth0, and when you have the main screen click the toggle button in the right bottom corner, and you should be presented with a pin error:
This pin error occurs because the ShipFast app is only configured, through the network security config file, to trust the pin for the certificate of its API backend. Any certificate present in the system trusted store or provided by the user will not be trusted.
If you look at the mitmproxy proxy terminal you will not be able to find any request from the app to the its own API backend being intercepted, but you will be able to find the ones made to the Auth0 server because that connection is not using certificate pinning:
NOTE: If you don't see any output in mitmproxy then double check that the emulator was started with the same WiFi IP address used to start mitmproxy.
So, we have now tested that certificate pinning is working correctly and protecting us from a normal MitM attack. I say normal because this attack doesn't repackage the mobile app to bypass the certificate pinning protections as I demonstrate here, nor does it use Frida to hook at runtime into the code that does the check in order to inject trust into the request.
Next let's see how Frida can be used to disable certificate pinning and allow the MitM attack to succeed.
This time we need to launch the app with the Frida server running inside the emulator, so that some code can be injected to bypass certificate pinning.
Start the app with Frida:
frida --codeshare sowdust/universal-android-ssl-pinning-bypass-2 -U -f com.criticalblue.shipfast.certificate_pinning --no-pause
Now login with Auth0 and when presented with the main screen, click the toggle button in the right bottom corner, and you should be able to keep interacting with the mobile app without seeing any pinning error message. However, if you look at the mitmproxy CLI you can see the requests being made to the API backend are now visible:
So we can see the full sequence of requests made during the user authentication flow with Auth0 and the two requests made to the ShipFast API backend.
Let’s select the request made to /v1/shipments/nearest_shipment and see its details:
Looking at the headers section of the request we can see that the `Authorization` and `Api-Key` headers are up for grabs so that they can be reused outside the mobile app, for example in automated scripts. Such scripts will now be able to impersonate the mobile app traffic because as far as the API backend will be concerned these scripted requests will look identical to legitimate requests.
Let’s also take a look into the response:
This information is very valuable for an attacker trying to automate attacks against the API backend, because now he has a full view of the life cycle of each request. For example, this approach was what allowed the ShipRaider hacker to build his web app around the ShipFast API backend:
Read more about the ShipFast and ShipRaider story on this blog post.
By understanding how the ShipFast mobile app communicates with its backend the ShipRaider hacker was able to build a web app that allows ShipFast drivers to select the shipment with the best gratuity. This is something that they can’t do in the mobile app because it cuts across the ShipFast company business model. Bypassing the genuine mobile app hurts the company reputation for its very fast and efficient delivery service. That reputation is based on drivers always being directed to the nearest parcel to be delivered, regardless of the gratuity offered, and this concept is broken by ShipRaider - leading to longer delivery times and lower service levels.
Bypassing certificate pinning is not too hard, just a little laborious, and allows an attacker to understand in detail how a mobile app communicates with its API, and then use that same knowledge to automate attacks or build other services around it.
Another takeaway is that the API backend cannot trust that any given API request comes from what it is expecting, namely a genuine and unmodified version of its mobile app uploaded to the official stores of Android and iOS, even if the API request contains a valid API key and/or user authentication credential.
Read this blog post to learn how ShipFast blocked the ShipRaider web app from accessing the ShipFast API, which now is locked down to only accept requests made from genuine and unmodified instances of the ShipFast mobile app.