Bypassing Android SSL Pinning with FRIDA

frida-feat-img

As a pentester, you may come into the need of bypassing security controls to be able to provide a more significant evaluation. SSL Pinning is one of the most important security controls for protecting the communication between the mobile client and the server, been able to bypass this control is an important to also evaluate the server the application is communicating with.


If you are using a black-box approach for pentesting an Android application, you will need a reliable way to intercept and decrypt the traffic between the application and the server.

In a black-box approach, the pentester is given nothing but a target and, in the case of Android mobile applications, that usually boils down to an apk file.

SSL Pinning is a must for protecting the communication.

There are many security test cases, both static and dynamic, that you can run against a mobile application. However, one of the most important cases is to verify whether or not the application implements SSL Pinning to protect the communication.

With SSL Pinning, an application will make sure to connect only to a set of whitelisted servers. And whitelisting is done through the server’s certificate or it’s public key; which is hardcoded into the application’s source code and validated before establishing a secure SSL/TLS communication channel.

SSL Pinning helps ensuring the security of the communication and reduces the risk of man-in-the-middle attacks, in which, an attacker is able to intercept, decrypt and even tamper the communication between two nodes in the network.

Checking if SSL Pinning is enabled

There is no doubt, SSL Pinning is a very important security control. Basically, if you are able to intercept and decrypt the traffic only by routing the traffic of an application through a proxy, there is a problem.

Even if you have to make the device trust your own certificate, by installing it directly on the device, and you are still able to intercept the traffic, there is also a problem. (Do note that the trust behavior for API 24 or greater has changed, user-installed certificates are no longer trusted by default, read more here).

Basically, if you are able to intercept the traffic without the pinned certificate and without running anything on the device, then SSL Pinning is missing and you have identified a high risk.

Blackbox?

Bypassing SSL Pinning gives you access to to analyzing and probing the communication sent and received from the server. It also gives you a more specific target, since now you know where data is flowing to and from.

But, how to bypass a control that is intended to keep attackers out of your application communication? In short, you need to either be able to run code as root (for rooted devices) or reverse the application and add your code (for non-rooted devices ), as mentioned here.

Enter, Frida, “a dynamic code instrumentation toolkit that let’s you inject snippets of Javascript or your own library into a native application“. It is mostly used to allow attaching to an application’s process (through ptrace) and change/override part of it’s behavior.

Getting your hands on bypassing SLL Pinning.

Next, we’ll see how to bypass SSL Pinning with Firda. We won’t be covering the entire environment setup (since that will take a lot of time). But I will be using my Ubuntu computer with VirtualBox and Genymotion for Android Emulation, I will also be using ADB (Android Debug Bridge) for communicating with the device and the community version of Burspsuite as a proxy.

env-lab-setup


Defining the Target

For this exercise we need a target, a mobile application for which we first check if SSL Pinning is enabled and then try to bypass it with the Frida framework. In this case we will be using the popular Twitter mobile application.

Since we are using Genymotion, we can just use the built-in Open Gapps functionality to have the Google apps, and more specifically, the Play Store application installed on our virtual device. Then we proceed to install the Twitter application and run it:

genymotion-twitter


First things first!

Let’s first check if you can intercept the traffic of the application by simple putting a proxy in the middle. Start your proxy (Burpsuite in this case) on port 8080 and on a specific interface address (192.168.0.9 in the image below):

java -jar burpsuite.jar

burpsuite-setup


You should also enable Invisible Proxying on the Request Handling tab.

Now, go to a browser and navigate to the proxy’s IP and port (http://192.168.0.9:8080) and grab the proxy’s certificate by clicking on CA Certificate:

burp-getting-ca


Once downloaded, push the certificate into the virtual device with the ADB push command:

./adb push cacert.der /sdcard/burp.cer

In the device go to Settings > Security > Credential Storage and select Install from SD Card, navigate to where the certificate is located and select it, enter a name and you will most likely be asked to set a Lock Screen PIN or a password (do it and you will see a “burp Installed” message )

virtual-device-install-burp-cert


With your proxy ready to capture traffic, go to the virtual device and into Settings > Wi-Fi > WiredSSID and long press on it, on the popup select Modify Network, on the Proxy dropdown select Manual and you will be able to specify which proxy to connect to (set it to the previous values 192.168.0.9:8080):

virtual-device-proxy-manual


Save the changes (might also be worth to disable/enable the the Wi-Fi). Run the application, try to login and see if you can intercept the traffic (you may need to enter some information and hit the arrow button):

genymotion-twitter-login-fail


The login traffic is not intercepted; it doesn’t show on the proxy and the application fails with “An error has occurred when logging in. Please try again later“.

Why we can’t intercept?

Let’s fire up Wireshark and check what is going on at network level. Attach Wireshark to the same interface your proxy is running on. Try to login and check the network traffic.

wireshark-certificate-unknown


You can see the the TLS handshake gives a fatal error (Level: Fatal, Description: Certificate Unknown), meaning that the certificate presented to the application (our proxy’s certificate) is different to the one used for pinning (in other words, pinning is enabled).

Using Frida

The first thing you need to do is get Frida, there are two components to this; the first is the frida-tools, which you can install on your workstation with the next command:

pip install frida-tools

After that you can just run the frida help to make sure it was correctly installed:

frida-help


Frida-server

The second part comes as an executable file that you have to download, copy into the virtual device and run. Go here and find the version you want to use, I’m using this one.

wget https://github.com/frida/frida/releases/download/12.2.23/frida-server-12.2.23-android-x86.xz

Once downloaded, use unxz to decompress the file:

unxz frida-server-12.2.23-android-x86.xz

Move the file into the virtual device (default path is /data/local/tmp/)

./adb push frida-server-12.2.23-android-x86 /data/local/tmp/frida-server

Give execution permissions to frida-server:

./adb shell chmod 755 /data/local/tmp/frida-server

And now, we go into the device and run the frida-server with the next command:

./frida-server &

frida-server-run


Frida-server

Now, check if frida is working correctly, for this, run the next command on your workstation:

frida-ps -U

You should see something like the following:

frida-ps-U


Pushing the proxy’s CA Certificate

In order to be able to intercept the traffic, frida needs to have access to your proxy’s CA certificate. We can use the same certificate we downloaded before.Push the certificate into the device and into the same location as the frida-server, name it cert-der.crt (below we will see why this is required).

./adb push cacert.der /data/local/tmp/cert-der.crt

Bypassing SSL Pinning

Now, we need to get the frida script that will let you override SSL connections to create and use our own Trust Manager. You can find the script here.

We will first see to use this script to bypass SSL Pinning and then we will analyze what the script does. With the script at hand, you can run the next command:

frida -U -f com.twitter.android -l sslpinning.js

You will see frida doing it’s thing:

frida-sslpinning-bypass


And the twitter application is ran on the device. As before, go into the Login screen and enter an email and password (foo@domain.com and foopass in this case), then hit the Login button:

twitter-login-sslpinning-bypass


And check your proxy, you will see that the traffic was intercepted:

burp-intercepted-traffic


Analyzing the frida script

Open the frida script and review it’s contents, you will see that with Javascript code we can create a Trust Manager containing our proxy’s CA cerificate and that this Trust Manager is used to override the SSL Context (whenever it is created).

Below we will see the most important parts of this frida script. On line 25, the script creates an instance of an x509 CertificateFactory:

cf = CertificateFactory.getInstance("X.509");

At line 28, it reads and loads the previously proxy’s CA certificate into a variable (fileInputStream):

var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");

On lines 34 and 35 we see that this variable is used to generate a certificate with the CertificateFactory:

var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
var ca = cf.generateCertificate(bufferedInputStream);

Lines 43 to 46 then create a KeyStore and sets the generated certificate as a certificate entry in the KeyStore:

var keyStoreType = KeyStore.getDefaultType();
var keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

From lines 50 to 52, the script creates a TrustManagerFactory (which gets initialized with the KeyStore previously created:

var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

Finally, on line 58, we see that the script is overloads the SSLContext’s init function and sends the created TrustManagerFactory as parameter:

SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {...

SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);

25 Comments

  1. Very good info. Lucky me I discovered your website by accident (stumbleupon). I have book marked it for later!

  2. Good post however I was wondering if you could write a litte more on this subject? I’d be very grateful if you could elaborate a little bit more. Thank you!

    1. Hello Jenette,

      Thanks for the comment. At the moment I’m not planning to write more about this topic, however, if you have any questions about the article I might be able to help. There is also another article similar to this one in here.

      Regards,
      Cristian

  3. Hi Cristian,

    I would like to thank you for such great content.

    I have an issue, SSL pinning doesn’t seem to work with the third-party APIs like, if a request is being made to firebase, as when communicating with the database or using OTP APIs, also if a form has a google ReCaptcha implemented. In the above-mentioned cases, the request isn’t getting intercepted, Is there a way to intercept it?

    Regards,
    Anirudh K.

    1. Hello Anirudh,

      Thanks for the comment, that’s a good question, it might be the case that those implementations are using a specific HTTPClient (like OkHttp3 or similar) and there are frida scripts created specifically for those cases, like this one.
      Personally, I have found cases where one of the scripts does not work at intercepting the traffic and other does (probably because of the reason stated above), I would recommend trying the other frida scrips as well, here are a few more you can check: here and here.
      Also, note that I have written a different post on bypassing ssl pinning with frida gadget that you might find useful.

      Regards,
      Cristian

    2. Hi again,

      Thank you for the reply, will get back to you with an update.

      Regards,
      Anirudh K.

    3. The Frida code by clubhouse, seems to work somewhat, but the I have still persists. I am sharing the APIs with the app is communicating but the SSL pinning bypass failing to intercept them.

      The APIs and URL causing issue:

      playatoms-pa.googleapis.com:443
      firebasestorage.googleapis.com:443
      http://www.google.com:443

      and the error looks like:

      Error Proxy The client failed to negotiate an SSL connection to firebasestorage.googleapis.com:443: Received fatal alert: certificate_unknown

    4. Do you receive any message on the frida console after that error comes up in the proxy?

      Going back to the initial approach described in the above post, have you already installed the proxy’s certificate on the device as mentioned? Did you try on a device with API 23? There are some differences in how certificates are trusted on 24+ (this is a limitation).

      Also, did you try this one I’ve previously shared? Which seems to be a universal bypass that does not require installing any certificate, any result?

      Regards,
      Cristian

    5. I’m facing the same issue… when I try to intercept traffic originated by Recaptcha component an SSL error occurs.

      I can view what is happening by using logcat:

      GoogleCertificatesRslt: not allowed : pkg=, sha256=[….

  4. I really like your blog.. very nice colors & theme.
    Did you design this website yourself or did you hire
    someone to do it for you? Plz reply as I’m looking to design my own blog and would like to find out where u got
    this from. many thanks

    1. Hi Dakota,

      Thanks for the comment, a friend helped me out with the graphical design, I will ask if he is still working on these kind of projects and if he is fine with me sharing his contact information.

      Regards,
      Cristian

    2. Here you go, this is his email: pcdiaz@gmail.com

      He is very good, great to work with and a good friend, I’m sure he will help you out for a fair price.

      Regards,
      Cristian

  5. Please let me know if you’re looking for a author for your
    weblog. You have some really good articles and I feel I would be a good asset.
    If you ever want to take some of the load off, I’d love to write some material for your blog in exchange
    for a link back to mine. Please blast me an e-mail if interested.
    Cheers!

    1. Hi Alena,

      Not at the moment, but, I’ll keep it in mind!

      Regards,
      Cristian

  6. Hello, I think your site could be having web browser compatibility problems.
    Whenever I look at your web site in Safari, it looks fine however when opening in Internet Explorer, it’s got some overlapping issues.

    I simply wanted to provide you with a quick heads up!
    Apart from that, great website!

    1. Hello Kent,

      Thanks, let me know exactly where are you seeing these overlapping issues.

      Regards,
      Cristian

  7. Does your blog have a contact page? I’m having problems locating it but, I’d like to send you an e-mail. I’ve got some recommendations for your blog you might be interested in hearing. Either way, great blog and I look forward to seeing it grow over time.

  8. Excellent way of explaining, and fantastic post to obtain information concerning my presentation focus, which i am going to present in academy.

  9. that’s great but bro i push frida server to the android but still show error can you. give me you whatspps fb etc to contact you?

Leave a Reply

Your email address will not be published. Required fields are marked *