In a previous article we saw how to protect the https communication channel between a mobile app and an API server with certificate pinning, and as promised at the end of that article we will now see how to bypass certificate pinning.
To demonstrate how to bypass certificate pinning we will use the same Currency Converter Demo mobile app that was used in the previous article.
In this article you will learn how to repackage a mobile app in order to make it trust custom ssl certificates. This will allow us to bypass certificate pinning.
Certificate Pinning Bypass Context
An attacker may want to intercept the communications between your mobile app and your API server in order to collect enough data to automate attacks against it, or just to modify or redirect your data on the fly. In my previous article you learned how to protect the https communication channel between your mobile app and the API server by implementing certificate pinning to keep the prying eyes of attackers at bay. However, luckily for them and unfortunately for us, it is possible to get around certificate pinning.
Bypassing certificate pinning in a mobile app can be achieved with the use of Instrumentation frameworks like Frida or Xposed, or by downloading the original APK and modifying the network security config file to trust in user supplied certificates and to disable certificate pinning. After the modification it is necessary to repackage the app and install it again in the device, after which it is possible to intercept the traffic again with a MitM attack.
Attackers do not only repackaged an app to use in their own devices, they also upload them to the Google Play store. A good example of this is a repackaged app which is the original, and which uses the original API server, but will display ads where generated revenue will go for the attacker, not to the app author. A further more sophisticated example is a repackaged app that will redirect the payments for in app purchases to the bank account of the attacker.
Setup
Clone the Currency Converter Demo
From Github you will need to git clone the Currency Converter Demo app:
git clone --branch 0.3.0 https://github.com/approov/currency-converter-demo.git && cd currency-converter-demo/mobile-app/android
Keystore
You can use your usual keystore or just create a new one with:
$ ./bin/create-keystore.sh
... some output omitted ...
---> Adding, if not already present, properties to your ./local.properties file
---> Edit your ./local.properties file and add the passwords you have used when you first created the keystore.
As mentioned in the previous output, you need to add the required passwords that will be used to sign the release by editing your ./app/local.properties
file. Now edit the file and add the password you entered for Enter keystore password:
to the ANDROID_KEYSTORE_PASSWORD
and ANDROID_PRIVATE_KEY_PASSWORD
properties.
Install the APKTOOL
The apktool is one of the most popular tools used to decompile Android APKs, and it will be the one we will be using too. Just follow their official documentation to install it.
Building a Release
Now that the setup is concluded you should be in the folder currency-converter-demo/mobile-app/android
, and to build a release you just need to use bash helper script:
./bin/build-release.bash
Before we repackage the mobile app I recommend you to follow these instructions to make sure that pinning is working with the release you have built.
Repackage a Mobile App
In order to repackage a mobile app we need to have its APK, and for that you can use adb to extract it directly from your device or you can use an online service to download it for you (not recommended for security reasons), but because we have access to the source code we will just use the APK from the release we have just built in the previous step.
Once we have our APK we need to unpack it, and for that we will use the apktool from a bash script, like:
./bin/unpack-apk.sh
If you are curious about how this works just take a sneak peak of the bash script.
The result of unpacking the APK will be stored at .local/apktool/decoded-apk
, and we will need to edit the file .local/apktool/decoded-apk/res/network_security_config.xml
to enable trust in user supplied certificates, so that the mobile will trust the certificate of the proxy that we will use to perform a MitM attack against the repackaged app.
To disable certificate pinning we need to remove all these lines:
<pin-set>
<!-- Pin for: currency-converter-demo.pdm.approov.io -->
<pin digest="SHA-256">qXHiE7hFX2Kj4ZCtnr8u8yffl8w9CTv6kE0U5j0o1XY=</pin>
<!-- Backup Pin for: currency-converter-demo.pdm.approov.io -->
<pin digest="SHA-256">47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=</pin>
</pin-set>
<!-- TrustKit Android API -->
<!-- enforce pinning validation -->
<trustkit-config enforcePinning="true" disableDefaultReportUri="true">
<!-- Add a reporting URL for pin validation reports -->
<report-uri>https://report.pdm.approov.io/pinning-violation/report</report-uri>
</trustkit-config>
Adding trust in custom certificates supplied by the user is as easy as adding the following line to the trusted anchors:
<certificates src="user" />
The final network security file for the repackaged app should look like this:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Official Android N API -->
<!--https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html-->
<domain-config>
<domain includeSubdomains="false" >currency-converter-demo.pdm.approov.io</domain>
<trust-anchors>
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</domain-config>
</network-security-config>
Now we are ready to repackage the mobile app, and we will use a bash script to help us with the task:
./bin/repackage-apk.sh
Note: the script will prompt you for the keystore and private key passwords.
The repackage APK should be now found at:
$ ls -al .local/apktool/decoded-apk/repackaged-and-signed.apk-rw-r--r-- 1 approov approov 1602366 Jul 15 16:03 .local/apktool/decoded-apk/repackaged-and-signed.apk
Certificate Pinning Bypass in Action
Now that we have repackaged the APK, is time to install it in our device:
adb install .local/apktool/decoded-apk/repackaged-and-signed.apk
Before we try to intercept its traffic with a MitM attack, let’s perform a smoke test to be sure it works, by opening it and try to convert the default value:
The repackaged app works as usual, thus it is time to perform a MitM attack to see if we can bypass the certificate pinning that was shipped with the original APK, and for this we will once more use the mitmproxy. To set up and have it running we just need to follow the Setup for the MitM Attack instructions, then we will see that we will be able to continue to do conversions:
While at the same time we intercept the traffic between the API server and the mobile app, without raising any certificate pinning exceptions:
Therefore, despite the fact that we have learned in a previous article how to implement certificate pinning to protect against MitM attacks, we have now learned how to bypass pinning in a device that the attacker controls. Bypassing pinning is also achievable when an attacker is able to trick a user into installing the repackaged mobile app, and this is an issue that the official Google Play store and the App store are still struggling with in 2019, because you can still find repackaged versions of some of the most popular apps there.
Conclusion
Protecting your mobile app and API server from attackers is not an easy task, and is done in incremental steps. It starts with good and secure coding practices as recommended by the OWASP Mobile Security Project, and will end up with In-App and API defense solutions.
In the next article I will walk you through a solution that will secure certificate pinning from being bypassed, and will allow you to update the certificate pins without releasing a new version of your mobile app. This mobile app attestation solution will be both an In-App and API defense tool. It will protect your mobile app from being repackaged, tampered with at runtime or MitM attacked, and at the same time will guarantee that the API only serves requests from your genuine mobile app.
These are bold claims, but once you see how easy it is to implement and how effective it is, you may wish you had discovered it earlier.
See you in my next article...
Top comments (0)