Penetration testing for iPhone applications – Part 5
In the first part of the article, we discussed traffic analysis for iPhone applications. The second, third and fourth parts of the article covered an in-depth analysis of insecure data storage locations on the iPhone. In this part, we will take a look at runtime analysis of iOS applications. In the next part of the series, we cover iOS 7, a subject I don't really have a handle on so I have passed the torch to one of my co-authors.
Runtime analysis allows an attacker to manipulate the application's behaviour at runtime to bypass security locks and access sensitive information from memory. Before getting into runtime analysis, first we will take a look at the iOS application architecture and its runtime protection features.
FREE role-guided training plans
iOS application architecture
iOS application is a zip archive with .ipa file extension. The zip file contains the executable binary and iTunesArtwork, which is used by iTunes to manage the application. The typical structure of an iOS application is shown in the image below.
The .app folder within the Payload directory contains the application binary, all the resources of the application like images and audio, a provisioning profile that specifies application permissions, and the code signature.
iOS application binary is ARM compiled and uses Mach-O (mach object) file format. Mach-O format consists of 3 main regions: header, load commands and segments/sections. The picture below illustrates the Mach-O file basic structure.
The Mach-O structure of an iOS application can be viewed using otool on a jailbroken device. Otool is available in the Darwin CC Tools package on Cydia.
Header:
It identifies the Mach-O file and contains basic file type information like target architecture and flags that affect the interpretation of rest of the file. To view the Mach-O header of an iOS application, connect the iPhone over SSH and execute the command below.
otool–h ApplicationBinary
Below is the Mach-O header of the Facebook iOS application.
Cputype and subtype values in the Mach-O header indicate the application's target architecture. The above image shows that the Facebook application is built for the ARM7 processor.
ARM7s (iPhone 5) = cputype 12/ subtype 11
ARM7 (iPhone 4 & 4S) = cputype 12/ subtype 9
ARM6 (iPhone 3GS) = cputype 12/ subtype 6
Applications that are built for multiple architectures contain more than one Mach-O file. These binaries are called fat binaries or universal binaries. To view the Mach-O header of a fat binary, run the command below on SSH terminal.
otool –arch all -hApplicationBinary
The above image shows that CardInfo application is compiled for ARM7 and ARM7s processors.
Load commands:
Load commands specify the layout and linkage characteristics of the file. It includes the initial layout of the file in virtual memory, the location of the symbol table, the execution state of main thread of the program and shared library details. Load commands (LC_ENCRYPTION_INFO) also define whether the application binary is encrypted or not. To view the load commands of an application, run the command below on SSH terminal.
Otool –VlApplicationBinary
Data:
Mach-O file contains the actual data in one or more segments. Each segment contains zero or more sections. Each section of a segment contains code or data of some particular type. The exact number and layout of segments and sections is specified by the load commands.
iOS application runtime protection features
The iOS platform provides a lot of runtime security features like ASLR, stack smashing protection and ARC. Understanding the runtime protection features is important for reversing and analyzing iOS applications.
Address space layout randomization:
ASLR is an important exploit mitigation technique introduced in iOS 4.3. ASLR makes the remote exploitation of memory corruption vulnerabilities significantly more difficult by randomizing the application objects' location in the memory. By default, iOS applications use limited ASLR and only randomize part of the objects in the memory.
In order to take full advantage of ASLR, the application should be compiled with the -fPIE –pie flag ("Generate Position-Dependent Code" build option in Xcode). In the latest version of the XCode, this flag is automatically checked by default. The image below compares the different memory sections for partial and full ASLR applications.
To find out whether the application is compiled with PIE flag or not, connect the iPhone over SSH and execute the command below.
Otool –VhApplicaitonBinary
The above image shows PIE at the end of the output. It indicates that the Facebook application is compiled with PIE flag.
Stack smashing protection:
Stack smashing protection is an exploit mitigation technique that protects against stack overflow attacks by placing a random value known as stack canary before local variables on stack. The stack canary is checked upon return of the function. In case of an overflow, the canary is corrupted, and the application is able to detect and protect against the overflow. In order to take advantage of the stack smashing protection, the application should be compiled with the –fstack-protector-all flag.
iOS applications which use the stack canaries will contain _stack_chk_fail and _stack_chk_guard symbols in the binary.To find out whether the application is protected with stack smashing protection or not, connect the iPhone over SSH and execute the command below.
Otool –I –v ApplicationBinary | grep stack
The result shown in the above image indicates that the Facebook application is using the stack smashing protection.
Automatic reference counting:
ARC is another exploit mitigation technique introduced in iOS 5. It protects applications from memory corruption vulnerabilities by moving the responsibility of memory management from the developer to the compiler. ARC can be enabled in an application within XCode by setting the compiler option "Objective-C Automatic Reference Counting" to "yes". By default it is marked as "yes".
iOS applications with ARC enabled will contain_objc_release symbols in the binary.To find out whether the application is using ARC or not, execute the command below on SSH terminal.
Otool –I –v ApplicationBinary | grep _objc_release
The result shown in the above image indicates that the Facebook application is compiled with ARC flag.
Runtime protection features an additional layer of security to the application. So during a pentest it's always best practice to implement runtime protection features on the application.
Reversing iOS applications
Objective-C is the primaly lanaguage used to develop native iOS applications. Objective-C is a dynamic language based on the principles of message passing. As it is a dynamic language, all the classes, methods and any other components are stored in the binary itself. This information can be extracted using the class-dump-z tool written by kennytm.
class-dump-z setup:
- On a JailBroken iPhone, install wget and unzip from Cydia.
- Connect to the iPhone over SSH and run the commands below.
>wget -U Mozilla/5.0 http://www.securitylearn.net/wp-content/uploads/tools/iOS/class-dump-z.zip
>unzip class-dump-z.zip
>mv class-dump-z /usr/bin
To dump the class information from an iOS application, navigate to the application's .app folder and run the command below.
>Class-dump-z ApplicationBinary
The image below shows the class dump of the Gmail iOS application. The class dump does not reveal any useful data as the Gmail binary is encrypted. Applications downloaded from the AppStore are encrypted using FairPlay DRM to protect the piracy.
To find out whether the application is encrypted or not, run the command below on the SSH terminal.
>Otoo –l ApplicationBinary | grep crypt
Cryptid 1 indicates that the application is encrypted. For unencrypted applications, the cryptid value is 0.
So in reversing iOS applications, often the first step includes removing the AppStore encryption. Removing this encryption allows an attacker to get a greater understanding of the internal class structure and how the application binary works, and allows them to get the binary in a suitable state for reverse engineering. Applications which are in-house distributed and self signed are not encrypted.
Decrypting iOS applications:
When an iOS application is launched, the loader decrypts it and loads it into memory. A pretty well established process exists to take advantage of this process and remove the FairPlay copy protection of an iOS application. iOS application decryption process includes these steps:
- Find the starting offset and the size of the encrypted data in the application binary.
- Find the memory loading address of the application (changes every time if the app is compiled with PIE).
- Dump the decrypted portion of the application from memory using a debugger (ex: gdb).
- Overwrite the application's encrypted area with the dumped binary data.
- Change the cryptid value to 0.
The complete decryption process has been automated by Cydia applications like Clutch and Rasticrac.
Decrypting the Gmail iOS Application with Clutch:
- On a JailBroken iPhone, go to Cydia and add the repo http://AppAddict.org/repo by navigating to Manage->Sources.
- Download ClutchPatched, ZIP and IPA Installer from Cydia.
- Connect to the iPhone over SSH and type the 'Clutch' command. It lists out all the applications installed on the iPhone.
- Supplying the application name to the Clutch will decrypt it and store the decrypted IPA file in the /var/root/Documents/Cracked/ folder. The image below shows that Clutch cracked the Gmail application and stored the decrypted file as /var/root/Documents/Cracked/Gmail-v2.2.0.8921.ipa.
- The cracked IPA file can be installed on the iPhone directly from SSH using the command below.
> installipa –c [iPAPath]
The image below shows the class dump of the decrypted Gmail application.
A full class dump of a decrypted application maps to the classes and methods and provides an insight into what's going on inside an application. Once the class dump is obtained, we can look into it for interesting classes, methods, and properties and perform a runtime analysis.
Runtime analysis with Cycript
Runtime analysis involves reversing and analyzing the application work flow to bypass security locks, performing authentication bypass attacks, accessing sensitive information from memory, breaking logical checks, and accessing restricted areas of the application. As Objective-C is a reflective lanaguage, it allows the modification of its own behaviour at runtime. On the iPhone, iOS application runtime can be modified easily using Cycript. Cycript is available in Cydia packages.
Cycript is a programming language designed to blend the barrier between Objective-C and JavaScript. Cycript allows hooking into a process, thus giving access to all of the classes and instance variables and methods within the application.
Before getting into runtime analysis, it is necessary to undestand the execution flow of an iOS application.
Objective-C is a superset of C, so its execution also begins with the main() function. When a user touches the application icon on the springboard, it calls the main() function. It in turn invokes the UIApplicationMain method. UIApplicationMain instantiates the UIApplication object, displays the GUI (windows, views), creates the application delegate and sets up the events cycle.
The application delegate monitors the high level actions/events in the application. With Cycript we can connect to the running process and get access to the UIApplication object. UIApplication is a singleton object that represents the application and acts as a central control. Gaining access to the UIApplication object in turn gives access to the application internals.
The power of Cycript is demonstrated in the following examples. For demonstration, I've used an older version of the Photo Vault application. Before hooking into the application process with Cycript first, grab the class dump of the application using class-dump-z.
Accessing Instance Variables with Cycript:
The Photo Vault application keeps private photos secure by protecting with a password. When we launch the application for the first time, it prompts the user to set a password. Later, the user has to enter the correct password in order to access the private photos. These steps explain how to grab the password from runtime using Cycript.
- Launch the Photo Vault application. It will prompt for a password.
- Connect to the iPhone over SSH and grab the process id using ps ax command.
- Hook into the application process using cycript –p [PID] command. Note: If you know the application name you can attach Cycript using cycript –p [ApplicationName] command.
- On the Cycript prompt, we can get the instance of the application either by invoking the [UIApplication sharedApplication] method or using the UIApp variable.
- To find out the application delegate, run UIApp.delegate command.
- Search the class dump for the application delegate PhotoVaultAppDelegate and look for its @interface (class dump will have @interface & @protocol directives). An interface contains the declaration of all the methods and the properties, whereas the protocol contains a group of related methods, which an object might call on its delegate.
- Looking at the properties of the application delegate shows an interesting property strPass. Access the value stored in the strPass using UIApp.delegate.strPass command.
- Bingo! It reveals the password to unlock the private photos. Type the password in the application and you will get access to the user's private photos.
Cycript also allows you to modify the instance varaibles, invoke instance methods and overwrite the existing methods directly from runtime.
What should you learn next?
Penetration Testing For iPhone Applications is going to be covered in a series of articles. In Part 6, we will take a look at method swizzling technqiues with Cycript and runtime analysis with GNU Debugger (gdb).
Sources
- Debunking NSLog Misconceptions
-
Hacking and Securing iOS Applications by Jonathan Zdziarski
-
"Apple iOS 4 Security Evaulation" by Dino Dai Zovi