Root detection & SSL pinning bypass with Frida Framework

null byte
7 min readJan 8, 2019

--

Another day with mobile application security assessments…

I generally carry out android application assessments so, I will focus mostly on the android platform. Moreover, I like android because it is open, allows a lot of customisations and it is based on the linux kernel.The protection mechanisms in mobile platforms really annoy during any security assessment. Generally, assessments are carried on a rooted android device/emulator as they provide better control and flexibility. But the security mechanisms written in an android application prove hindrance during such an assessment.

When it comes to security assessments, it would not be good to not mention the ubiquitous “BURPSUITE”. It is an interception tool to observe and manipulate the https traffic between a client and a server. But, SSL pinning checks don’t allow “BURPSUITE” to do an MITM and intercept the requests and responses. More information on SSL pinning can be found here and here. So, what do we do now??

There are many workarounds for the above problems. One is the static approach where the “apk” is decoded with tools like “apktool” and the particular logic is changed in the “smali” files and then the “apk” is re-packaged again. But, this method is likely to fail if there is any “tamper-detection” code in place. The other method uses a dynamic approach where the particular logic is changed while the application is running which means code would be injected at runtime in the process. As we can see, the second method doesn’t require re-packaging. Also, at times, some adb tricks help e.g. the adb activity manager can be used to directly start the next activity to bypass any logic present in the preceding activity.

Here, in this post, I will be following the dynamic approach. I will be using the “Frida Framework” to bypass the above mentioned checks (root detection and SSL pinning) on a real android device. First, let us understand what exactly “Frida” is.

Frida

In short, it is a dynamic instrumentation framework, which enables function hooking and allows to provide a definition to it during runtime. Basically, it injects JavaScript code into a process. Suppose, there is a function called “foo” in a program with a specific body/implementation. Using “Frida”, one can change the body/implementation of the “foo” function during runtime. “Frida” supports a variety of platforms like Windows, macOS, GNU/Linux, iOS, Android, and QNX. More information on “Frida” can be found here.

There are three modes of operation in “Frida”, viz. Injected, Embedded & Preloaded. Here, I will be using the injected mode of operation. More information on these modes can be found here.

One disadvantage of the injected mode is that it requires a rooted device. On the other hand, the embedded mode of operation doesn’t require a rooted device but requires re-packaging of the “apk” i.e. the “Frida gadget” (a shared library) needs to be embedded in the “apk”. So, it depends upon the situation as to which mode of operation one needs to follow during an assessment.

Sample Implementation in android with JavaScript

Java.perform(function(){var sample_class = Java.use("fully qualified class name");//Creating object of the above class
var obj = sample_class.$new()
sample_class.function_name.implementation = function(){//new logic for the function here};});

In the above example, the function within the sample class is overwritten with a new implementation using JavaScript API for Frida. For more information please refer this and this.

Before starting off, let’s set up the lab.

Lab Setup

The following are required to setup the android lab for dynamic instrumentation with “Frida”.

One may follow this guide to configure BURPSUITE with the android device and for setting up “Frida” one may follow this.

Steps

  1. Connect the android device to the computer and make sure that Developer Options and USB Debugging are turned on as shown in figure 1.
  2. Then check if the device is detected with adb tool as shown in figure 2.
  3. Find the ABI with adb tool by issuing the command
    adb shell getprop ro.product.cpu.abi as shown in figure 3.
  4. Download the correct Frida server (for android) from here and push it to the android device with adb as shown in figure 5.
  5. Change the permissions of the Frida server to make it executable and run it in the background by issuing the commands as shown in figure 5.
  6. Install Frida tools on the computer by typing the following in a terminal pip install frida-tools and check if Frida tools are able to communicate with the running Frida server as shown in figure 6. Here, we try to list down the running processes on the android device.
  7. Push the BURPSUITE certificate (in crt format) to the android device as shown in figure 7 and install it on the device.
Figure 1: Turning USB debugging on
Figure 2: Listing device with adb
Figure 3: Checking CPU architecture
Figure 4: Decompressing and rename Frida server binary
Figure 5: Running Frida server on the android device
Figure 6: Listing running process on android device
Figure 7: Pushing BURPSUITE certificate (with crt extension) to the android device

Analysing the root detection logic

Load the android package (apk)in JADX tool and search for the terms “root”, “rooted” etc. In my application, I found that the “isDeviceRooted” function is responsible for the root detection logic. If a boolean “false” is returned from this function then it would mean that the device is not rooted.

Figure 8: Root detection code
Figure 9: Root detection code

When the application is run on a rooted device, a message is displayed and the application terminates.

Root detection bypass

I quickly wrote an implementation for the function responsible for root detection in JavaScript.

Please note that the above implementation for root detection bypass may vary from application to application.

I typed the following in a terminal to run the android application and inject the JavaScript code to overwrite the implementation of the “isDeviceRooted” function. Hence, the root detection logic was bypassed using Frida.

frida -l root-detection-bypass.js -U -f com.redacted.app --no-pause
Figure 10: Injecting JavaScript code into process

Analysing SSL pinning logic

Searching for terms like “pinning”, “SSLContext”, “KeyStore”, “TrustManagers” etc. in JADX, revealed the function which is responsible for SSL pinning. There was an “init” function inside the “MyVolley” class of the application. For more information on SSL pinning in android please refer this and this. On trying to intercept the traffic with BURPSUITE, the following certificate error was encountered due to certificate pinning checks.

Figure 11: SSL pinning checks in action

SSL pinning bypass

After analysing the function for some time, I wrote the following JavaScript code to redefine the implementation of the function responsible for the logic. Also, combining it with the previous root detection bypass script and thus, producing the final script as follows.

Please note that the above script was created by referring the Java source code of the application and thus may vary from application to application.

Running the above script as shown below to disable root detection checks and SSL pinning checks in the android application.

frida -l root-ssl-pin-bypass.js -U -f com.redacted.app --no-pause
Figure 12: Injecting the final script with Frida
Figure 13: SSL pinning checks bypassed

Thanks for reading!

Some useful resources to follow

--

--

null byte

A security researcher, wandering in the midst of bytes.