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
/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
/var/mobile/Containers/Data/Application/3F622664-0B3C-438F-A0EC-EA734AAA8BD1/Library/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 127.0.0.1:8556
cy# var message = \[\[UIAlertView alloc\] init\];
#"<UIAlertView: 0x1437c3c60; frame = (0 0; 0 0); layer = <CALayer: 0x281a7a700>>"
cy# message.title = "jpalanco";
"jpalanco"
cy# message.message = "This is an injected alert";
"This is an injected alert"
cy# \[message addButtonWithTitle:@"Dismiss"\];
0
cy# \[message show\];
cy#
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 127.0.0.1 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!