iOS app pen testing : Harnessing the power of r2frida for runtime manipulation

Reading time: Reading time 3 minutes

You might already know a fair bit about r2frida by now - its definition, usage, features, installation, and examples - something we discussed in the previous blog of this series. 

In case you missed out on it, you can find it here.

In this blog, we will explore how r2frida can be instrumental in manipulating an iOS app's runtime.


Table of Content


Loading an iOS Application for analysis

Today, we'll Look into the analysis of the DVIA-v2 (Damn Vulnerable iOS Application) and use the power of r2frida to complete the login challenge through runtime manipulation. First off, I will need to install the DVIA-v2 application on my device. I will use a tool called ios-deploy to install the ipa file onto the device. It is good practice to have AppSync Unified installed on the device if you want to deal with app signing issues, as it bypasses Installd's signature checks.

Let's use frida-ps to get the list of apps installed on the iOS device.

frida-ps -Uai

An image of all the apps installed on a given iOS device by using the command frida-ps


When executing the command frida-ps -Uai, you will receive essential information such as the active and installed application's Process ID (PID), name, and identifier.

Once we obtain the application identifier, we can proceed to spawn the application using r2frida for further analysis.

r2 frida://spawn/usb//com.appknox.DVIAswiftv2

A screenshot showing how you can spawn an iOS application and pause its execution flow.


Executing this command spawns the application and pauses its execution flow. To resume the application's execution, enter the :dc command in the r2frida session.

Entering the :dc command to resume the execution of an iOS application


Furthermore, the :i command helps obtain information about the target (pid, name, home, arch, bits, etc.).

the :i command helps get information about the iOS application's target

 

Analyzing the login challenge

If you go to the "Runtime Manipulation" portion of the DVIA application, you will see the login challenge. This challenge has an easy-to-use interface with two kinds of login buttons and fields for entering a username and password.

An image showing the login challenge of runtime manipulation on the DVIA application

To analyze the classes for this challenge, you can list the classes in the application with the :ic command. To narrow down the results, use the filter :ic~+String. Let's check the classes related to the runtime manipulation challenge by filtering the classes list with :ic~+runtimemanip

Checking the runtime manipulation-related classes by filtering them with the :ic~+runtimemanip command


As you can see, there is a class called DVIA_v2.RuntimeManipulationDetailsViewController. Let's check the methods in the class, so running :ic DVIA_v2.RuntimeManipulationDetailsViewController gives the list of methods present in the class.

List of methods present in a class (DVIA_v2.RuntimeManipulationDetailsViewController) in the iOS application


This class doesn't contain any methods related to validating the login, so we can ignore this class and check other class names related to the login challenge. Let's check if there are any classes with names having a login.

Checking whether there are any classes with the name "login" in the iOS application


As you can see, there is a LoginValidate class. This could be responsible for the logic of the login challenge. Let's check if there are any methods to check the login validation.

The presence of the "loginvalidate class" proves the logic of the iOS app login challenge

The LoginValidate class has a method named isLoginValidated. Let's confirm if this method really checks the validation of the login challenge by tracing the method using :dtf command. As observed in the earlier section, the address of isLoginValidated is represented by 0x00000001007d6080. The following command can be executed to trace the execution of this method.

:dtf 0x00000001007d6080

Using a command to check the validation of the login challenge in the iOS application


This command returns a true response, which means it is executed correctly. Now, let's enter the wrong credentials and try to log in using Login method 1.

An image showing the login failure due to wrong credentials


As you can see, the trace command returned 0x0, which means the login failed due to incorrect credentials.

Hooking with r2Frida

Now we know that the isLoginValidated method returns 0x0 for incorrect credentials. With all the info we need, we can easily play around with the isLoginValidated method. By changing the return value to 0x1, we can make the app think the wrong credentials are correct. There are two ways we can modify the return value of a method. The first one uses Frida Interceptor API, and the other one uses the r2frida command :dif

The Interceptor API allows us to easily hook functions or code sections provided they have a valid memory address. It takes NativePointers matching the target function address and lets us attach them to some interesting callbacks onEnter and onLeave.

:eval Interceptor.attach(ptr(0x00000001007d6080), {onLeave: function (retval) {retval.replace(0x1)}})

Are you wondering what this command does? We're using the :eval command in r2frida to run JavaScript code. This JavaScript code hooks into the function at a specific memory address (0x00000001007d6080). When this function finishes running, it changes the function's return value to 1 before it actually returns.

Using the :eval command in r2frida to run the JavaScript code


Again, log in with the wrong credentials and observe the r2frida. The return value is changed to 0x1, making the login a success.

Observing r2frida by logging in with the wrong credentials


So, using :eval to run javascript code with interceptor API, we were able to bypass the login challenge. Let’s look into another way to change the return value of a function using the r2frida inbuilt command :dif

Changing the function's return value using the r2frida inbuilt command :dif to check if the login challenge can be bypassed

Using :dif1, we can replace the function return value with 1 and bypass the login challenge.

Bypassing an iOS app's login challenge by using the :dif1 command to replace the function return value with 1

And there you have it: we successfully bypassed the login challenge using two methods.


Conclusion

As we draw the curtains on our exploration of r2frida, it's evident that this tool is a force to be reckoned with in iOS security. By seamlessly blending static analysis and dynamic instrumentation techniques, r2frida empowers researchers to uncover vulnerabilities and strengthen defenses. So, here's to harnessing the power of r2frida and making our digital world a safer place, one app at a time.

 

Published on Jun 17, 2024
Vinay Kumar Rasala
Written by Vinay Kumar Rasala
Vinay Kumar Rasala serves as a security research associate at Appknox, a leading security suite for automating mobile security in enterprises. He specializes in ethical hacking and penetration testing and has actively collaborated with numerous enterprises, strengthening their APIs and mobile and web apps against cyber threats.
Vinay is passionate about exploring new technologies, mainly iOS tweaks, reverse engineering, and programming. In his free time, he enjoys playing open-world games and experimenting with cooking.

Questions?

Chat With Us

Using Other Product?

Switch to Appknox

2 Weeks Free Trial!

Get Started Now