hacktricks/mobile-apps-pentesting/ios-pentesting/basic-ios-testing-operations.md
2022-04-05 18:24:52 -04:00

436 lines
22 KiB
Markdown

# Basic iOS Testing Operations
## Getting the UDID of an iOS device
{% hint style="info" %}
Perform this actions having **connected** the device to the computer via **USB** and having the **device** **unlocked**.
{% endhint %}
The UDID is a 40-digit unique sequence of letters and numbers to identify an iOS device. You can find the UDID of your iOS device on macOS Catalina onwards in the **Finder app**, as iTunes is not available anymore in Catalina. Just select the connected iOS device in Finder and **click on the information under the name of the iOS** device to iterate through it. Besides the UDID, you can find the serial number, IMEI and other useful information.
![](<../../.gitbook/assets/image (471).png>)
If you are using a macOS version before Catalina, you can find the [UDID of your iOS device via iTunes](http://www.iclarified.com/52179/how-to-find-your-iphones-udid), by selecting your device and clicking on "Serial Number" in the summary tab. When clicking on this you will iterate through different metadata of the iOS device including its UDID.
It is also possible to get the UDID via various command line tools on macOS while the device is attached via USB:
* By using the [I/O Registry Explorer](https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/TheRegistry/TheRegistry.html) tool `ioreg`:
```bash
$ ioreg -p IOUSB -l | grep "USB Serial"
| "USB Serial Number" = "9e8ada44246cee813e2f8c1407520bf2f84849ec"
```
* By using [ideviceinstaller](https://github.com/libimobiledevice/ideviceinstaller) (also available on Linux):
```bash
$ brew install ideviceinstaller
$ idevice_id -l
316f01bd160932d2bf2f95f1f142bc29b1c62dbc
```
* By using the system\_profiler:
```bash
$ system_profiler SPUSBDataType | sed -n -e '/iPad/,/Serial/p;/iPhone/,/Serial/p;/iPod/,/Serial/p' | grep "Serial Number:"
2019-09-08 10:18:03.920 system_profiler[13251:1050356] SPUSBDevice: IOCreatePlugInInterfaceForService failed 0xe00002be
Serial Number: 64655621de6ef5e56a874d63f1e1bdd14f7103b1
```
* By using instruments:
```bash
$ instruments -s devices
```
## Accessing the Device Shell
After jailbreaking the device you should have installed some new app manager like **Cydia**.
### SSH
In order to enable SSH access to your iOS device you can install the **OpenSSH** **package**. Once installed, you can access your device via ssh running `ssh root@<device_ip_address>`, which will log you in as the root user:
```bash
$ ssh root@192.168.197.234
root@192.168.197.234's password:
iPhone:~ root#
```
When accessing your iOS device via SSH consider the following:
* The default users are `root` and `mobile`.
* The default password for both is `alpine`.
> Remember to change the default password for both users `root` and `mobile` as anyone on the same network can find the IP address of your device and connect via the well-known default password, which will give them root access to your device.
### **Connect to a Device via SSH over USB**
During a real black box test, a reliable Wi-Fi connection may not be available. In this situation, you can use usbmuxd to connect to your device's SSH server via USB.
Connect macOS to an iOS device by installing and starting iproxy:
```bash
$ brew install libimobiledevice
$ iproxy 2222 22
waiting for connection
```
The above command maps port `22` on the iOS device to port `2222` on localhost. You can also [make iproxy run automatically in the background](https://iphonedevwiki.net/index.php/SSH\_Over\_USB) if you don't want to run the binary every time you want to SSH over USB.
With the following command in a new terminal window, you can connect to the device:
```bash
$ ssh -p 2222 root@localhost
root@localhost's password:
iPhone:~ root#
```
> Small note on USB of an iDevice: on an iOS device you cannot make data connections anymore after 1 hour of being in a locked state, unless you unlock it again due to the USB Restricted Mode, which was introduced with iOS 11.4.1
### On-device Shell App
While usually using an **on-device shell** (terminal emulator) might be very tedious compared to a remote shell, it can prove handy for debugging in case of, for example, network issues or check some configuration. For example, you can install [NewTerm 2](https://repo.chariz.io/package/ws.hbang.newterm2/) via Cydia for this purpose (it supports iOS 6.0 to 12.1.2 at the time of this writing).
In addition, there are a few jailbreaks that explicitly disable incoming SSH _for security reasons_. In those cases, it is very convenient to have an on-device shell app, which you can use to first SSH out of the device with a reverse shell, and then connect from your host computer to it.
Opening a reverse shell over SSH can be done by running the command `ssh -R <remote_port>:localhost:22 <username>@<host_computer_ip>`.
On the on-device shell app run the following command and, when asked, enter the password of the `mstg` user of the host computer:
```bash
ssh -R 2222:localhost:22 mstg@192.168.197.235
```
On your host computer run the following command and, when asked, enter the password of the `root` user of the iOS device:
```bash
$ ssh -p 2222 root@localhost
```
### **Forgotten Password**
If you forget your password and want to reset it to the default `alpine`:
1. Edit the file `/private/etc/master.passwd` on your jailbroken iOS device using an on-device **terminal** or using apps like **Filza** or **iFile**
2. Find the lines:
```bash
root:xxxxxxxxx:0:0::0:0:System Administrator:/var/root:/bin/sh
mobile:xxxxxxxxx:501:501::0:0:Mobile User:/var/mobile:/bin/sh
```
3. Change `xxxxxxxxx` to `/smx7MYTQIi2M` (which is the hashed password `alpine`)
4. Save and exit
## Data Transfer
### Copying App Data Files via SSH and SCP
As we know now, files from our app are stored in the Data directory. You can now simply archive the Data directory with `tar` and pull it from the device with `scp`:
```bash
iPhone:~ root# tar czvf /tmp/data.tgz /private/var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693
iPhone:~ root# exit
$ scp -P 2222 root@localhost:/tmp/data.tgz .
```
### Using iFunbox
[**iFunbox**](https://www.i-funbox.com/en/page-download.html) is a GUI application that can be used for several things (uploading/downloading files among them).\
Another GUI tool for this purpose is [**iExplorer**](https://macroplant.com/iexplorer).
{% hint style="info" %}
Starting in iOS version 8.4, Apple has **restricted the third-party managers to access to the application sandbox**, so tools like iFunbox and iExplorer no longer display/retrieve files from apps installed on the device if the device isn't jailbroken.
{% endhint %}
### Using Objection
When you are starting objection (`objection --gadget com.apple.mobilesafari explorer`) you will find the prompt within the Bundle directory.
```bash
org.owasp.MSTG on (iPhone: 10.3.3) [usb] # pwd print
Current directory: /var/containers/Bundle/Application/DABF849D-493E-464C-B66B-B8B6C53A4E76/org.owasp.MSTG.app
```
Use the `env` command to get the directories of the app and navigate to the Documents directory.
```bash
org.owasp.MSTG on (iPhone: 10.3.3) [usb] # cd /var/mobile/Containers/Data/Application/72C7AAFB-1D75-4FBA-9D83-D8B4A2D44133/Documents
/var/mobile/Containers/Data/Application/72C7AAFB-1D75-4FBA-9D83-D8B4A2D44133/Documents
```
With the command `file download <filename>` you can download a file from the iOS device to your host computer and can analyze it afterwards.
```bash
org.owasp.MSTG on (iPhone: 10.3.3) [usb] # file download .com.apple.mobile_container_manager.metadata.plist
Downloading /var/mobile/Containers/Data/Application/72C7AAFB-1D75-4FBA-9D83-D8B4A2D44133/.com.apple.mobile_container_manager.metadata.plist to .com.apple.mobile_container_manager.metadata.plist
Streaming file from device...
Writing bytes to destination...
Successfully downloaded /var/mobile/Containers/Data/Application/72C7AAFB-1D75-4FBA-9D83-D8B4A2D44133/.com.apple.mobile_container_manager.metadata.plist to .com.apple.mobile_container_manager.metadata.plist
```
You can also upload files to the iOS device with `file upload <local_file_path>`.
## Obtaining and Extracting Apps
### Getting the IPA File from an OTA Distribution Link
During development, apps are sometimes provided to testers via over-the-air (OTA) distribution. In that situation, you'll receive an itms-services link, such as the following:
```
itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist
```
You can use the [ITMS services asset downloader](https://www.npmjs.com/package/itms-services) tool to download the IPA from an OTA distribution URL. Install it via npm:
```bash
$ npm install -g itms-services
```
Save the IPA file locally with the following command:
```bash
# itms-services -u "itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist" -o - > out.ipa
```
### Acquiring the App Binary
1. **From an IPA**:
If you have the IPA (probably including an already decrypted app binary), unzip it and you are ready to go. The app binary is located in the main bundle directory (.app), e.g. `Payload/Telegram X.app/Telegram X`. See the following subsection for details on the extraction of the property lists.
> On macOS's Finder, .app directories are opened by right-clicking them and selecting "Show Package Content". On the terminal you can just `cd` into them.
2. From a **Jailbroken device**:
If you don't have the original IPA, then you need a jailbroken device where you will **install the app** (e.g. via App Store). Once installed, you need to **extract the app binary from memory and rebuild the IPA file**. Because of DRM, the app binary file is encrypted when it is stored on the iOS device, so simply pulling it from the Bundle (either through SSH or Objection) will not be sufficient to reverse engineer it (read next section).
### Decryption (Manual)
Unlike an Android Application, the binary of an iOS app **can only be disassembled** and not decompiled.\
When an application is submitted to the app store, Apple first verifies the app conduct and before releasing it to the app-store, **Apple encrypts the binary using** [**FairPlay**](https://developer.apple.com/streaming/fps/). So the binary download from the app store is encrypted complicating ting the reverse-engineering tasks.
However, note that there are other **third party software that can be used to obfuscate** the resulting binaries.
In order to run the encrypted binary, the device needs to decrypt it in memory. Then, it's possible to **dump the decrypted binary from the memory**.
First, check if the binary is compiled with the PIE (Position Independent Code) flag:
```bash
otool -Vh Original_App #Check the last word of the last line of this code
Home:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 EXECUTE 47 6080 NOUNDEFS DYLDLINK TWOLEVEL PIE
```
If it's set you can use the script [`change_macho_flags.py`](https://chromium.googlesource.com/chromium/src/+/49.0.2623.110/build/mac/change\_mach\_o\_flags.py) to remove it with python2:
```bash
python change_mach_o_flags.py --no-pie Original_App
otool -Vh Hello_World
Hello_World:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 EXECUTE 22 2356 NOUNDEFS DYLDLINK TWOLEVEL MH_NO_HEAP_EXECUTION
```
Now that the PIE flag isn't set, the OS will load the program at a **fixed starting location** every-time. In order to find this **location** you can use:
```bash
otool -l Original_App | grep -A 3 LC_SEGMENT | grep -A 1 __TEXT
segname __TEXT
vmaddr 0x00004000
```
Then, it's necessary to extract the the memory range that needs to be dumped:
```bash
otool -l Original_App | grep -A 4 LC_ENCRYPTION_INFO
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 16384
cryptsize 17416192
cryptid 0
```
The value of **`cryptoff`** indicated the starting address of the encrypted content and the **`cryptsize`** indicates the size of the encrypted content.
So, the `start address` to dump will be `vmaddr + cryptoff` and the `end address` will be the `start address + cryptsize`\
In this case: `start_address = 0x4000 + 0x4000 = 0x8000` __ and `end_address = 0x8000 + 0x109c000 = 0x10a4000`
With this information it's just necessary to run the application in the jailbroken device, attach to the process with gdb (`gdb -p <pid>`) and dump the memory:
```bash
dump memory dump.bin 0x8000 0x10a4000
```
Congrats! You have decrypted the encrypted section in dump.bin. Now **transfer this dump to your computer and overwrite the encrypted section with the decrypted** one:
```bash
dd bs=1 seek=<starting_address> conv=notrunc if=dump.bin of=Original_App
```
There is one more step to complete. The application is still **indicating** in its metadata that it's **encrypted**, but it **isn't**. Then, when executed, the device will try to decrypt the already decrypted section and it's going to fail.\
However, you can use tools like [**MachOView**](https://sourceforge.net/projects/machoview/) to change this info. Just open the binary and set the **cryptid** to 0:
![](<../../.gitbook/assets/image (470).png>)
### Decryption (Automatically)
#### frida-ios-dump
You can use tools like [**frida-ios-dump**](https://github.com/AloneMonkey/frida-ios-dump) to **automatically remove the encryption and an app**.
First, make sure that the configuration in **Frida-ios-dump** `dump.py` is set to either localhost with port 2222 when using **iproxy**, or to the actual IP address and port of the device from which you want to dump the binary.
Now you can safely use the tool to **enumerate** the **apps** **installed**:
```bash
$ python dump.py -l
PID Name Identifier
---- --------------- -------------------------------------
860 Cydia com.saurik.Cydia
1130 Settings com.apple.Preferences
685 Mail com.apple.mobilemail
834 Telegram ph.telegra.Telegraph
- Stocks com.apple.stocks
...
```
and you can **dump** **one** of the listed binaries:
```bash
$ python3 dump.py -u "root" -p "<PASSWORD>" ph.telegra.Telegraph
Start the target app ph.telegra.Telegraph
Dumping Telegram to /var/folders/qw/gz47_8_n6xx1c_lwq7pq5k040000gn/T
[frida-ios-dump]: HockeySDK.framework has been loaded.
[frida-ios-dump]: Load Postbox.framework success.
[frida-ios-dump]: libswiftContacts.dylib has been dlopen.
...
start dump /private/var/containers/Bundle/Application/14002D30-B113-4FDF-BD25-1BF740383149/Telegram.app/Frameworks/libswiftsimd.dylib
libswiftsimd.dylib.fid: 100%|██████████| 343k/343k [00:00<00:00, 1.54MB/s]
start dump /private/var/containers/Bundle/Application/14002D30-B113-4FDF-BD25-1BF740383149/Telegram.app/Frameworks/libswiftCoreData.dylib
libswiftCoreData.dylib.fid: 100%|██████████| 82.5k/82.5k [00:00<00:00, 477kB/s]
5.m4a: 80.9MB [00:14, 5.85MB/s]
0.00B [00:00, ?B/s]Generating "Telegram.ipa"
```
After this, the `Telegram.ipa` file will be created in your current directory. You can validate the success of the dump by removing the app and reinstalling it (e.g. using [**ios-deploy**](https://github.com/ios-control/ios-deploy) `ios-deploy -b Telegram.ipa`). Note that this will only work on jailbroken devices, as otherwise the signature won't be valid.
#### flexdecrypt
In order to **obtain the ipa file** from an installed application you can also use the tool [**flexdecrypt**](https://github.com/JohnCoates/flexdecrypt) or a wrapper of the tool called [**flexdump**](https://gist.github.com/defparam/71d67ee738341559c35c684d659d40ac)**.**\
In any case you will need to **install flexdecrypt in the device** running something like:
```markup
wget https://github.com/JohnCoates/flexdecrypt/releases/download/1.1/flexdecrypt.deb
dpkg -i flexdecrypt.deb
rm flexdecrypt.deb
```
and in order to use **flexdump**:
```bash
apt install zip unzip
wget https://gist.githubusercontent.com/defparam/71d67ee738341559c35c684d659d40ac/raw/30c7612262f1faf7871ba8e32fbe29c0f3ef9e27/flexdump -P /usr/local/bin; chmod +x /usr/local/bin/flexdump
flexdump list #List apps
flexdump dump Twitter.app #Create .ipa file from app
```
#### r2flutch
[**r2flutch**](https://github.com/as0ler/r2flutch) is a tool that uses **radare** and **frida** to **decrypt** and **dump ios apps>**
See the **github** for more information.
## Installing Apps
When you install an application without using Apple's App Store, this is called **sideloading**. There are various ways of sideloading which are described below. On the iOS device, the actual installation process is then handled by the **installd** **daemon**, which will **unpack** and **install** the application. To integrate app services or be installed on an iOS device, all **applications must be signed with a certificate issued by Apple**. This means that the application can be installed only after successful code signature verification. On a jailbroken phone, however, you can **circumvent this security feature with** [**AppSync**](http://repo.hackyouriphone.org/appsyncunified), a package available in the Cydia store. It contains numerous useful applications that leverage jailbreak-provided root privileges to execute advanced functionality. **AppSync is a tweak that patches installd**, allowing the installation of fake-signed IPA packages.
Different methods exist for installing an IPA package onto an iOS device, which are described in detail below.
> Please note that iTunes is no longer available in macOS Catalina. If you are using an older version of macOS, iTunes is still available but since iTunes 12.7 it is not possible to install apps.
#### Cydia Impactor
[Cydia Impactor](http://www.cydiaimpactor.com) was originally created to jailbreak iPhones, but has been rewritten to sign and install IPA packages to iOS devices via sideloading (and even APK files to Android devices). Cydia Impactor is available for Windows, macOS and Linux. A [step by step guide and troubleshooting steps are available on yalujailbreak.net](https://yalujailbreak.net/how-to-use-cydia-impactor/).
#### libimobiledevice
On Linux and also macOS, you can alternatively use [libimobiledevice](https://www.libimobiledevice.org), a cross-platform software protocol library and a set of tools for native communication with iOS devices. This allows you to install apps over a USB connection by executing ideviceinstaller. The connection is implemented with the USB multiplexing daemon [usbmuxd](https://www.theiphonewiki.com/wiki/Usbmux), which provides a TCP tunnel over USB.
The package for libimobiledevice will be available in your Linux package manager. On macOS you can install libimobiledevice via brew:
```bash
$ brew install libimobiledevice
$ brew install ideviceinstaller
```
After the installation you have several new command line tools available, such as `ideviceinfo`, `ideviceinstaller` or `idevicedebug`.
```bash
# The following command will show detailed information about the iOS device connected via USB.
$ ideviceinfo
# The following command will install the IPA to your iOS device.
$ ideviceinstaller -i iGoat-Swift_v1.0-frida-codesigned.ipa
...
Install: Complete
# The following command will start the app in debug mode, by providing the bundle name. The bundle name can be found in the previous command after "Installing".
$ idevicedebug -d run OWASP.iGoat-Swift
```
#### ipainstaller
The IPA can also be directly installed on the iOS device via the command line with [ipainstaller](https://github.com/autopear/ipainstaller). After copying the file over to the device, for example via scp, you can execute ipainstaller with the IPA's filename:
```bash
$ ipainstaller App_name.ipa
```
#### ios-deploy
On macOS you can also use the **ios-deploy** tool to install iOS apps from the command line. You'll need to unzip your IPA since ios-deploy uses the app bundles to install apps.
```bash
$ unzip Name.ipa
$ ios-deploy --bundle 'Payload/Name.app' -W -d -v
```
After the app is installed on the iOS device, you can simply start it by adding the `-m` flag which will directly start debugging without installing the app again.
```bash
$ ios-deploy --bundle 'Payload/Name.app' -W -d -v -m
```
#### Xcode
It is also possible to use the Xcode IDE to install iOS apps by doing the following steps:
1. Start Xcode
2. Select **Window/Devices and Simulators**
3. Select the connected iOS device and click on the **+** sign in **Installed Apps**.
#### Allow Application Installation on a Non-iPad Device
Sometimes an application can require to be used on an iPad device. If you only have iPhone or iPod touch devices then you can force the application to accept to be installed and used on these kinds of devices. You can do this by changing the value of the property **UIDeviceFamily** to the value **1** in the **Info.plist** file.
```markup
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
</array>
</dict>
</plist>
```
It is important to note that changing this value will break the original signature of the IPA file so you need to re-sign the IPA, after the update, in order to install it on a device on which the signature validation has not been disabled.
This bypass might not work if the application requires capabilities that are specific to modern iPads while your iPhone or iPod is a bit older.
Possible values for the property [UIDeviceFamily](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple\_ref/doc/uid/TP40009252-SW11) can be found in the Apple Developer documentation.