hacktricks/ios-pentesting/ios-basics.md

125 lines
13 KiB
Markdown

# iOS Basics
## Privilege Separation and Sandbox
Applications the user can access run as the **mobile** user while critical system processes run as **root**.
However, the sandbox allows better control over actions that processes and applications can perform.
For example, even if two processes run as the same user \(mobile\), they are **not allowed to access or modify each other's data**.
Each application is installed under **`private/var/mobile/Applications/{random ID}`**
Once installed, applications have limited read access to some system areas and functions \(SMS, phone call...\). If an application wants to access a **protected area,** a **pop-up requesting permission** appears.
## Data Protection
App developers can leverage the iOS _Data Protection_ APIs to implement **fine-grained access control** for user data stored in flash memory. The APIs are built on top of the **Secure Enclave Processor** \(SEP\). The SEP is a coprocessor that provides **cryptographic operations for data protection and key management**. A device-specific hardware key-the **device UID** \(Unique ID\)-is **embedded in the secure enclave**, ensuring the integrity of data protection even when the operating system kernel is compromised.
When a **file is created** on the disk, a new **256-bit AES key is generated** with the help of secure enclave's hardware based random number generator. The **content of the file is then encrypted with the generated key**. And then, this **key is saved encrypted with a class key** along with **the class ID,** with **both data encrypted by the system's key,** inside the **metadata** of the file.
![](../.gitbook/assets/image%20%28474%29.png)
For decrypting the file, the **metadata is decrypted using the system's key**. Then u**sing the class ID** the **class key is retrieved** **to decrypt the per-file key and decrypt the file.**
Files can be assigned to one of **four** **different** **protection** classes, which are explained in more detail in the [iOS Security Guide](https://www.apple.com/business/docs/iOS_Security_Guide.pdf):
* **Complete Protection \(NSFileProtectionComplete\)**: A key derived from the user passcode and the device UID protects this class key. The derived key is wiped from memory shortly after the device is locked, making the data inaccessible until the user unlocks the device.
* **Protected Unless Open \(NSFileProtectionCompleteUnlessOpen\)**: This protection class is similar to Complete Protection, but, if the file is opened when unlocked, the app can continue to access the file even if the user locks the device. This protection class is used when, for example, a mail attachment is downloading in the background.
* **Protected Until First User Authentication \(NSFileProtectionCompleteUntilFirstUserAuthentication\)**: The file can be accessed as soon as the user unlocks the device for the first time after booting. It can be accessed even if the user subsequently locks the device and the class key is not removed from memory.
* **No Protection \(NSFileProtectionNone\)**: The key for this protection class is protected with the UID only. The class key is stored in "Effaceable Storage", which is a region of flash memory on the iOS device that allows the storage of small amounts of data. This protection class exists for fast remote wiping \(immediate deletion of the class key, which makes the data inaccessible\).
All class keys except `NSFileProtectionNone` are encrypted with a key derived from the device UID and the user's passcode. As a result, decryption can happen only on the device itself and requires the correct passcode.
Since iOS 7, the default data protection class is "Protected Until First User Authentication".
\*\*\*\*[**FileDP**](https://github.com/abjurato/FileDp-Source) is a program that you can upload and use inside the IPhone to **inspect the data protection class** of each file.
### The Keychain
A keychain is an **encrypted** **container** where every application can **store** **sensitive** pieces of **information** and only the same app \(or authorised apps\) can retrieve the contents.
The iOS **generated its own password for the keychain** and **stores** an **encrypted** version of this key in the device. This password is encrypted with AES using an AES key created by a **PBKDF2** function of the **user's passcode + salt** \(the 256 bit device **UID** **only** **accessible** to the secure **enclave chipset** on the device\). Due to the use of this device UID as salt, a device won't be able to decrypt the keychain of a different device even knowing the users passcode.
Access to the Keychain is managed by the **`securityd`** daemon, which grants access according to the app's `Keychain-access-groups`, `application-identifier`, and `application-group` entitlements.
The [Keychain API](https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html) includes the following main operations:
* `SecItemAdd`
* `SecItemUpdate`
* `SecItemCopyMatching`
* `SecItemDelete`
The only ways to try to BF this password is dumping the encrypted key and BF the passcode + salt \(the **pbkdf2** function uses **at least 10000 iteration**s\). Or trying to **BF inside the device** to avoids BFing the salt, however, secure enclave ensures there is at least a **5s delay between 2 failed password attempts**.
You can configure **data protection for Keychain items** by setting the `kSecAttrAccessible` key in the call to `SecItemAdd` or `SecItemUpdate`.The following configurable [accessibility values for kSecAttrAccessible](https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values#1679100) are the Keychain Data Protection classes:
* **`kSecAttrAccessibleAlways`**: The data in the Keychain item can **always be accessed**, regardless of whether the device is locked.
* **`kSecAttrAccessibleAlwaysThisDeviceOnly`**: The data in the Keychain item can **always** **be** **accessed**, regardless of whether the device is locked. The data **won't be included in an iCloud** or local backup.
* **`kSecAttrAccessibleAfterFirstUnlock`**: The data in the Keychain item can't be accessed after a restart until the **device has been unlocked once** by the user.
* **`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`**: The data in the Keychain item can't be accessed after a restart until the **device has been unlocked once** by the user. Items with this attribute do **not migrate to a new device**. Thus, after restoring from a backup of a different device, these items will not be present.
* **`kSecAttrAccessibleWhenUnlocked`**: The data in the Keychain item can be accessed **only while the device is unlocked** by the user.
* **`kSecAttrAccessibleWhenUnlockedThisDeviceOnly`**: The data in the Keychain item can be accessed **only while the device is unlocked** by the user. The data **won't be included in an iCloud or local backup**.
* **`kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly`**: The data in the Keychain can be accessed **only when the device is unlocked**. This protection class is **only available if a passcode is set** on the device. The data w**on't be included in an iCloud or local backup**.
**`AccessControlFlags`** define the mechanisms with which users can authenticate the key \(`SecAccessControlCreateFlags`\):
* **`kSecAccessControlDevicePasscode`**: Access the item via a passcode.
* **`kSecAccessControlBiometryAny`**: Access the item via one of the fingerprints registered to Touch ID. Adding or removing a fingerprint won't invalidate the item.
* **`kSecAccessControlBiometryCurrentSet`**: Access the item via one of the fingerprints registered to Touch ID. Adding or removing a fingerprint _will_ invalidate the item.
* **`kSecAccessControlUserPresence`**: Access the item via either one of the registered fingerprints \(using Touch ID\) or default to the passcode.
Please note that keys secured by Touch ID \(via `kSecAccessControlBiometryAny` or `kSecAccessControlBiometryCurrentSet`\) are protected by the Secure Enclave: The Keychain holds a token only, not the actual key. The key resides in the Secure Enclave.
The iPhone uses the **passcode introduced by the user unlocking the device to decrypt the secrets in the keychain**.
iOS uses the _**AppIdentifierPrefix**_ \(Team ID\) and the _**BundleIdentifier**_ \(provided by the dev\) to enforce **access control oven keychain items**. Then, the same team **can** **configure** **2 apps to share keychain items**.
When a backup process is initiated the keychain **data backed up remains encrypted and the keychain password isn't included in the backup**.
{% hint style="warning" %}
**In a jailbroken device the keychain isn't protected.**
{% endhint %}
#### **Keychain Data Persistence**
On iOS, when an application is uninstalled, the Keychain data used by the application is retained by the device, unlike the data stored by the application sandbox which is wiped. In the event that a **user sells their device without performing a factory reset, the buyer of the device may be able to gain access to the previous user's application accounts and data by reinstalling** the same applications used by the previous user. This would require no technical ability to perform.
There's no iOS API that developers can use to force wipe data when an application is uninstalled. Instead, developers should take the following steps to prevent Keychain data from persisting between application installations:
* When an application is first launched after installation, wipe all Keychain data associated with the application. This will prevent a device's second user from accidentally gaining access to the previous user's accounts. The following Swift example is a basic demonstration of this wiping procedure:
```objectivec
let userDefaults = UserDefaults.standard
if userDefaults.bool(forKey: "hasRunBefore") == false {
// Remove Keychain items here
// Update the flag indicator
userDefaults.set(true, forKey: "hasRunBefore")
userDefaults.synchronize() // Forces the app to update UserDefaults
}
```
* When developing logout functionality for an iOS application, make sure that the Keychain data is wiped as part of account logout. This will allow users to clear their accounts before uninstalling an application.
## Objective-C and Swift Basics
**Objecttive-C** has a **dynamic runtime**, so when an Objective-C program is executed in iOS, it calls libraries whose **address are resolved at runtime** by comparing the name of the function sent in the message against a list of all the function names available.
At the beginning, only apps created by Apple run the iPhones, so they had **access to everything** as they were **trusted**. However, when Apple **allowed** **third party applications,** Apple just removed the headers files of the powerful functions to "hide" them to developers. However, developers found that "safe" functions needed a few of these undocumented functions and just creating a **custom header file with the names of the undocumented functions, it was possible to invoke this powerful hidden functions.** Actually, Apple, before allowing an app to be published, check if the app calls any of these prohibited functions.
Then, Swift appeared. As **Swift is statically bound** \(it doesn't resolve the address of the functions in runtime like Objective-C\), it can be checked more easily the calls a Swift program is going to make via static code analysis.
## Device Management
From iOS version 6, there is **built-in support for device management** capability with fine grain controls that allows an organisation to control the corporate apple devices.
The enrolment can be **initiated by the user installing an agent** in order to access the corporate apps. In this case the device usually belongs to the user.
Or the **company can indicate the serial numbers** of the bought devices or the purchase order ID and specify the MDM profile to install on those devices. Note that Apple **doesn't allow to enrol a particular device this way twice**. Once the first profile is deleted the user needs to give consent to install another one.
The user can see the installed policies in _**Settings**_ --> _**General**_ --> _**Profile and Device Management**_
As these MDM policies are checking and limiting other applications, they are **running with more privileges**.
A MDM policy can **enforce** **users** to have a **passcode** set with a **minimun** password **complexity**.
The profiles are tied to the deviceID, **signed** and **encrypted** by the MDM server and **tamper** **proof**. They **cannot** be **removed** without **losing** all the **corporate** **data**.
MDM profiles allow to **wipe** all the **data** if there are X **failed** password **attempts**. Also, the **admin** can **remote** **wipe** the iPhone whenever via the MDM interface.
MDM agents will **check** also for **possible jailbreaks of the device**, as this is very dangerous state for an iPhone.