hacking, reversing,

Pentesting iOS Apps with OSX and a Jailbroken device

Jose Ramon Palanco Jose Ramon Palanco Follow Apr 05, 2020 · 10 mins read
Pentesting iOS Apps with OSX and a Jailbroken device
Share this

Today we will explain how to perform a basic security assessment on an iOS Application using Mac. For this assessment it is mandatory your IOS device is jailbroken. I assume you have some experience with BurpSuite. In this article, we will perform some basic tests on iGoat. This is a iOS vulnerable App for mobile app pentesters.

Setting up your iOS device

For installing iGoat, you may need to install AppCake.  Start Cydia and add AppCake’s repository by going to Manage -> Sources -> Edit -> Add and enter https://cydia.iphonecake.com/.

Now add frida’s repository, for that repeat the previous steps and enter https://build.frida.re. You should now be able to find and install the Frida package which lets Frida inject JavaScript into apps running on your iOS device. This happens over USB, so you will need to have your USB cable handy, though there’s no need to plug it in just yet.

For code injection, we will install cycript from Cydia. Cycript allows to explore and modify running applications on either iOS using a hybrid of Objective-C++ and JavaScript syntax through an interactive console that features syntax highlighting and tab completion. For running Cycript we may install Cyrun, so add http://www.tateu.net/repo/ like you did with the other repos and install cyrun and cycript.

Now you can download iGoat. Once downloaded, go to Files, select Share option on “iGoat” file -> Copy to AppCake and in a few seconds it will be signed and ready for install in the download section of AppCake.

Setting up your OSX

Frida is a dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers. You can inject your own scripts into black-box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.

We will install frida tools to interact with the phone:

sudo pip3 install frida-tools

Now you can execute frida:

Joses-MacBook-Pro:~ jpalanco$ frida-ps -U

Waiting for USB device to appear…

Frida will wait until you plug the USB, once you plug it, you will get a list of all the process running:

 PID  Name
---- --------------------------------------------------------
 907  App Store
 947  Netflix
 975  Spotify
 894  Spotlight
 983  Telegram
 984  Work Chat
 901  YouTube
 910  iMessageAppsViewService
 526  ACCHWComponentAuthService
 847  AppPredictionWidget
 887  AppSSODaemon
 515  AppleCredentialManagerDaemon
 613  AssetCacheLocatorService
 987  BTLEServer
 549  BlueTool
 905  CAReportingService
 606  CMFSyncAgent
 938  CacheDeleteAppContainerCaches
 897  CategoriesService

Okay, frida is running.

Objection is a runtime exploration toolkit powered by Frida, aimed at mobile platforms. iOS only, for now, objection aims to allow you to perform various security-related tasks on unencrypted iOS applications, at runtime, on non-jailbroken iOS devices

Okay, let’s install objection:

sudo pip3 install objection

Okay, now we have the shell. Let’s analyze iGoat:

Joses-MacBook-Pro:~ jpalanco$ objection -g iGoat explore
Using USB device \`iPad 4\`
Agent injected and responds ok!

     \_   \_         \_   \_
 \_\_\_| |\_|\_|\_\_\_ \_\_\_| |\_|\_|\_\_\_ \_\_\_
| . | . | | -\_|  \_|  \_| | . |   |
|\_\_\_|\_\_\_| |\_\_\_|\_\_\_|\_| |\_|\_\_\_|\_|\_|
      |\_\_\_|(object)inject(ion) v1.9.0

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

\[tab\] for command suggestions
com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] #

We will use "pwd print" to display the current path:

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # pwd print                                                                                                                                
Current directory: /private/var/containers/Bundle/Application/D5D3778B-71CC-4305-9D19-175140564E81/iGoat.app

To display the environment variables just type “env”:

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # env                                                                                                                                      

Name               Path
----------------- -------------------------------------------------------------------------------------------
BundlePath         /private/var/containers/Bundle/Application/D5D3778B-71CC-4305-9D19-175140564E81/iGoat.app
CachesDirectory    /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/Caches
DocumentDirectory  /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Documents
LibraryDirectory   /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library

We can use “cd” to chage to diferent directories and “ls” to list the files:

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # cd /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library                                                  
com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # ls                                                                                                                                                                                                                                                                          NSFileType      Perms  NSFileProtection    Read    Write    Owner         Group         Size    Creation                   Name
------------ ------- ------------------ ------ ------- ------------ ------------ ------ ------------------------- -----------------------
Directory         493  n/a                 True    True     mobile (501)  mobile (501)  96.0 B  2020-04-06 13:39:53 +0000  Caches
Directory         493  n/a                 True    True     mobile (501)  mobile (501)  96.0 B  2020-04-06 13:40:03 +0000  Saved Application State
Directory         493  n/a                 True    True     mobile (501)  mobile (501)  96.0 B  2020-04-06 13:40:05 +0000  SplashBoard
Directory         493  n/a                 True    True     mobile (501)  mobile (501)  96.0 B  2020-04-06 13:39:53 +0000  Preferences

Readable: True  Writable: True
com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # cd Preferences                                                                                                                           
com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # ls                                                                                                                                       
NSFileType      Perms  NSFileProtection                      Read    Write    Owner         Group         Size     Creation                   Name
------------ ------- ------------------------------------ ------ ------- ------------ ------------ ------- ------------------------- -----------------------
Regular           384  CompleteUntilFirstUserAuthentication  True    True     mobile (501)  mobile (501)  405.0 B  2020-04-06 13:40:03 +0000  com.swaroop.iGoat.plist

Readable: True  Writable: True

If we find a plist file we can display it easily with “ios plist cat file.plist”

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # ios plist cat com.swaroop.iGoat.plist                                                                                                    
    WebDatabaseDirectory = "/var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/Caches";
    WebKitLocalStorageDatabasePathPreferenceKey = "/var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/Caches";
    WebKitOfflineWebApplicationCacheEnabled = 1;
    WebKitShrinksStandaloneImagesToFit = 1;

We can also download or upload files using “file download file” and “file upload file”. It is very interesting finding for sqlite files, inspect them, modify them and upload again.

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # file download com.swaroop.iGoat.plist                                                                                                    
Downloading /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/Preferences/com.swaroop.iGoat.plist to com.swaroop.iGoat.plist
Streaming file from device...
Writing bytes to destination...
Successfully downloaded /var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/Preferences/com.swaroop.iGoat.plist to com.swaroop.iGoat.plist

Injecting code

We will log on to the device using ssh. Now we will try to inject some code into iGoat app:

Jose-Ramons-iPad:/tmp root# cyrun -n iGoat -e
applicationName: iGoat is running (3397)
    executableName: iGoat
    bundleIdentifier: com.swaroop.iGoat
    Cycript is active: com.apple.springboard
    Device is not passcode locked
    Tweak Mode
WARNING - Cycript is active but it looks like the bundleIdentifier you are trying to enable it for does not match!
    You cannot enable Cycript in a new Process while it is still running in old one
Do you want to connect to the current Process (y or n)? y
Success, You may now run
    cycript -r
cy# var message = \[\[UIAlertView alloc\] init\];
#"<UIAlertView: 0x1437c3c60; frame = (0 0; 0 0); layer = <CALayer: 0x281a7a700>>"
cy# message.title = "jpalanco";
cy# message.message = "This is an injected alert";
"This is an injected alert"
cy# \[message addButtonWithTitle:@"Dismiss"\];
cy# \[message show\];



Analyzing communications

For this, we will use BurpSuite.

In Burp, go to the “Proxy” tab and then the “Options” tab.

In the “Proxy Listeners” section, click the “Add” button.

In the “Binding” tab, in the “Bind to port:” box, enter a port number that is not currently in use, e.g. “8082”.

Then select the “All interfaces” option, and click “OK”.

Note: You could alternatively edit the existing default proxy listener to listen on all interfaces. However, using different listeners for desktop and mobile devices enables you to filter these in the Proxy history view.

The Proxy listener should now be configured and running.

In your iOS device, go to the “Settings” menu.

Tap the “Wi-Fi” option from the “Settings” menu.

If your device is not already connected to the wireless network you are using, then switch the “Wi-Fi” button on, find your network in the list, and tap it to connect. Enter your network password if prompted.

Tap the “i” (information) option next to the name of your network.

Under the “HTTP PROXY” title, tap the “Manual” tab.

In the “Server” field, enter the IP address of the computer that is running Burp.

In the “Port” field, enter the port number configured in the “Proxy Listeners” section earlier, in this example “8082”.

Now, open Safari on your IOS device and go to http://burp/ and click on “CA Certificate”

You will be prompted with a message in the “Install Profile” window. Tap “Install”.

You will then be prompted with a warning message. Again, tap “Install”.

A further message will appear entitled “Install Profile”. Again, tap “Install”.

The Burp CA certificate should now be installed on your iOS device. Tap “Done”.

On some versions of iOS you may need to go to “Enable Full Trust for the PortSwigger CA”.

You can configure this setting at Settings -> General -> About -> Certificate Trust Settings.

Certificate Pinning is not enforced on iGoat, but in real-world applications, we may not see traffic, because the application doesn’t like your BurpSuite certificate. We can bypass Certificate Pinning with objection:

com.swaroop.iGoat on (iPad: 13.1.2) \[usb\] # ios sslpinning disable                                                                                                                   
(agent) Hooking common framework methods
(agent) Found NSURLSession based classes. Hooking known pinning methods.
(agent) Hooking lower level SSL methods
(agent) Hooking lower level TLS methods
(agent) Hooking BoringSSL methods
(agent) Registering job tvo5kvfkhs. Type: ios-sslpinning-disable


Dumping a decrypted IPA

Even we can dump files using objection, this method is more convenient. We can extract the IPA to our computer to perform local analysis. We will need to install some requirements:

$ brew install usbmuxd

We will need to create a public key for access ssh without a password.

Now lets clone frida-ios-dump:

$ git clone https://github.com/AloneMonkey/frida-ios-dump.git

In another terminal, type:

$ iproxy 2222 22

Go back to the main terminal and launch:

Joses-MacBook-Pro:frida-ios-dump jpalanco$ ./dump.py iGoat
\[Errno None\] Unable to connect to port 2222 on or ::1
Try specifying -H/--hostname and/or -p/--port
Joses-MacBook-Pro:frida-ios-dump jpalanco$ ./dump.py iGoat
Start the target app iGoat
Dumping iGoat to /var/folders/x6/tdpf6b4s1zx6dhyx837d01yr0000gn/T
\[frida-ios-dump\]: Load Realm.framework success. 
start dump /private/var/containers/Bundle/Application/D5D3778B-71CC-4305-9D19-175140564E81/iGoat.app/iGoat
iGoat.fid: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 3.36M/3.36M \[00:00<00:00, 13.2MB/s\]
start dump /private/var/containers/Bundle/Application/D5D3778B-71CC-4305-9D19-175140564E81/iGoat.app/Frameworks/Realm.framework/Realm
Realm.fid: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6.01M/6.01M \[00:00<00:00, 22.6MB/s\]
ServerCommunicationExerciseController\_iPhone.nib: 33.4MB \[00:01, 20.0MB/s\]                                                                                                           
0.00B \[00:00, ?B/s\]Generating "iGoat.ipa"
0.00B \[00:00, ?B/s\]

In a few seconds, we will have the decrypted ipa file on our computer. For analyzing the contents we will uncompress:

Then Show Package Contents:

And we will have access to the files:

Decompiling the classes

We can use class-dump to decompile the classes. You can download it from http://stevenygard.com/projects/class-dump/

Joses-MacBook-Pro:~ jpalanco$ /Volumes/class-dump-3.5/class-dump   /Users/jpalanco/Projects/frida-ios-dump/Payload/iGoat.app/iGoat | head -n 30
2020-04-07 12:47:55.586 class-dump\[5552:270907\] Warning: Parsing instance variable type failed, inUse
//     Generated by class-dump 3.5 (64 bit).
//     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.

#pragma mark Function Pointers and Blocks

typedef void (*CDUnknownFunctionPointerType)(void); // return type and parameters are unknown

typedef void (^CDUnknownBlockType)(void); // return type and parameters are unknown

#pragma mark Named Structures

struct CBLBlobKey {
    unsigned char bytes[20];

struct CBLChangesOptions {
    unsigned int _field1;
    _Bool _field2;
    _Bool _field3;
    _Bool _field4;
    _Bool _field5;

struct CBLGeoPoint {
    double x;
    double y;

Reversing the app

At this point, we will install ghidra:

$ brew cask install ghidra

Launch ghidra:

$ ghidraRun

We will create a project and import the iGoat mach-o file. After a few minutes, Ghidra will finish the analyses:

Happy hacking!

Jose Ramon Palanco
Written by Jose Ramon Palanco Follow
Jose Ramón Palanco founded Dinoflux at 2014, a Threat Intelligence startup acquired by Telefonica, currently he works for 11paths since 2018. He worked also for Ericsson at R&D department and Optenet (Allot). He studied Telecommunications Engineering at the University of Alcala de Henares and Master of IT Governance at the University of Deusto. He has been a speaker at OWASP, ROOTEDCON, ROOTCON, MALCON, and FAQin... He has published several CVE and different open source tools for cybersecurity like nmap-scada, ProtocolDetector, escan, pma, EKanalyzer, SCADA IDS, ...