iOS
iOS Platform¶
Important Folders¶
Applications: /private/var/containers/Bundle/Application
System Applications:
Application Data Directories: /private/var/mobile/Containers/Data/Application/
Install Programs: /usr/local/sbin
Keyboard Cache: /private/var/mobile/Library/Keyboard/dynamic-text.dat
Screenshot Directory: /private/var/mobile/Media/DCIM/100APPLE
Get data from application sandbox directory
Push notifications¶
TODO
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
Firebase¶
Check Firebase settings by finding the https://\<firebaseProjectName\>.firebaseio.com/.json
request
Crypto¶
New Crypto should use the Swift Crypto Library.
Apple CryptoKit- New for iOS 13
Things to Grep for:
- CommonCryptor
- CCCrypt
- CCCryptorCreate
- SecRandomCopyBytes
T2 Chip¶
Official Apple Documentation on the T2 Chip
Contains Device specific AES 256-bit hardware key that only the crypto engine can access. This is used to encrypt all of the data on the device.
Creating a key in the secure enclave:*
// private key parameters
let privateKeyParams = [
kSecAttrLabel as String: "privateLabel",
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: "applicationTag",
] as CFDictionary
// public key parameters
let publicKeyParams = [
kSecAttrLabel as String: "publicLabel",
kSecAttrIsPermanent as String: false,
kSecAttrApplicationTag as String: "applicationTag",
] as CFDictionary
// global parameters
let parameters = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPublicKeyAttrs as String: publicKeyParams,
kSecPrivateKeyAttrs as String: privateKeyParams,
] as CFDictionary
var pubKey, privKey: SecKey?
let status = SecKeyGeneratePair(parameters, &pubKey, &privKey)
if status != errSecSuccess {
// Keys created successfully
}
File Data Protections¶
- Every file on the file system can have a different iOS File Protection set.
- This encryption key is derived from the UID and the PBKDF2 of the passcode.
- Each file has a different key that is stored in the File Metadata
Listing the files and their corresponding File Protections in Objection:
Listing the files and their corresponding File Protections in Frida:
frida -U -f com.tinyspeck.chatlyio --no-pause -l /opt/Memory/Mobile/frida_iOS_helper_functions.js -e "getDataProtectionKeysForAllPaths()"
____
/ _ | Frida 12.8.7 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Spawning `com.tinyspeck.chatlyio`...
Spawned `com.tinyspeck.chatlyio`. Resuming main thread!
[iOS Device::com.tinyspeck.chatlyio]-> getDataProtectionKeysForAllPaths()
[
{
"fileProtectionKey": "NSFileProtectionCompleteUntilFirstUserAuthentication",
"path": "/private/var/mobile/Containers/Data/Application/2E1B100C-CD63-4241-AAF9-58E6C4DFC09C/StoreKit/receipt"
},
{
"fileProtectionKey": "NSFileProtectionNone",
"path": "/private/var/mobile/Containers/Data/Application/2E1B100C-CD63-4241-AAF9-58E6C4DFC09C/.com.apple.mobile_container_manager.metadata.plist"
},
{
"fileProtectionKey": "NSFileProtectionCompleteUntilFirstUserAuthentication",
"path": "/private/var/mobile/Containers/Data/Application/2E1B100C-CD63-4241-AAF9-58E6C4DFC09C/Library/Caches/com.hackemist.SDImageCache/default/e062188527582103ec63e729fc92c3af.png"
},
{
"fileProtectionKey": "NSFileProtectionCompleteUntilFirstUserAuthentication",
"path": "/private/var/mobile/Containers/Data/Application/2E1B100C-CD63-4241-AAF9-58E6C4DFC09C/Library/Caches/Snapshots/com.tinyspeck.chatlyio/[email protected]"
},
[...]
NSFileProtectionComplete: The class key is protected with a key derived from the user passcode and the device UID. Shortly after the user locks a device (10 seconds, if the 'Require Password' setting is set to 'Immediately'), the decrypted class key is discarded, rendering all data in this class inaccessible until the user enters the passcode again.
NSFileProtectionCompleteUntilFirstUserAuthentication: This class behaves in the same way as the 'NSFileProtectionComplete' attribute, except that the decrypted class key is not removed from memory when the device is locked. The protection in this class has similar properties to desktop full-disk encryption, and protects data from attacks that involve a reboot.
NSFileProtectionCompleteUnlessOpen: Some files may need to be written while the device is locked. A good example of this is a mail attachment downloading in the background. This behavior is achieved by using asymmetric elliptic curve cryptography. The ephemeral public key for the agreement is stored alongside the wrapped per-file key. As soon as the file is closed, the per-file key is wiped from memory. To open the file again, the shared secret is recreated using the Protected Unless Open class's private key and the file's ephemeral public key, which are used to unwrap the per-file key that is then used to decrypt the file.
NSFileProtectionNone: This class key is only protected by device level encryption. Since all the keys needed to decrypt files in this class are stored on the device, the encryption only affords the benefit of fast remote wipe.
Keychain¶
- Data is stored in a SQLLite Database but can only be accessed through the Keychain API.
- Can be accessed through the API with the
SecItemAdd
,SecItemUpdate
,SecItemCopyMatching
,SecItemDelete
Accessibility Values:
- 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 won't be included in an iCloud or local backup.
Control Flags:
- 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. Data with this flag are stored in the Secure Enclave itself
- kSecAccessControlBiometryCurrentSet
: Access the item via one of the fingerprints registered to Touch ID. Adding or removing a fingerprint will invalidate the item. Data with this flag are stored in the Secure Enclave itself
- kSecAccessControlUserPresence
: Access the item via either one of the registered fingerprints (using Touch ID) or default to the passcode.
Dump all keychain data using keychain_dumper.
Note
Keychain Data is not wiped by default when an app is removed
iOS Versions¶
iOS 11 Changes¶
Certificates in iOS 11 & 12
Root Certs have to be installed then manually trusted.
Settings -> General -> About -> Certificate Trust Settings
iOS Sandbox¶
The App Sandbox restricts apps to specific containers.
Apps are prevented from executing mmap
and mmprotect
to making pages executable if they are writable.
Sandblaster is a tool for reversing (decompiling) binary Apple sandbox profiles.
SSH¶
Through Network:
ssh -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null [email protected]
Through USB:
python2 /opt/iOS/needle/needle/libs/usbmuxd/tcprelay.py -t 22:2222
ssh -p 2222 -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null [email protected]
Files¶
Binary Cookie File¶
Binary Cookie Files are stored in the Application directory and can contain sensitive cookies.
Use BinaryCookieReader.py to read these files.
Example:
python BinaryCookieReader.py Cookies.binarycookies
PList Files¶
Plist files can either be a XML data or a Binary equivalent of xml data.
Example:
file some_file.plist
plist some_file.plist
SQLite¶
Example:
SQLite cipher¶
Realm Databases¶
https://realm.io/docs/objc/latest/
https://realm.io/docs/swift/latest/
How to encrypt databases:
// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}
Couchbase Lite Databases¶
https://github.com/couchbase/couchbase-lite-ios
YapDatabase¶
https://github.com/yapstudios/YapDatabase
Dump Process Memory¶
LLDB:
1. Pull an iOS-compatible version of the debugserver binary (requires Xcode and command-line tool installation)
hdiutil attach /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/<LATESTiOSVERSION>/DeveloperDiskImage.dmg
cp /Volumes/DeveloperDiskImage/usr/bin/debugserver .
2. Push debugserver binary to device
3. chmod +x the binary on the device
4. Run
./debugserver *:1234 -a <TARGETAPP>
on the iOS device5. Run
lldb
on your testing machine6. On LLDB run the commands
process connect connect://<DEVICEIP>:1234
process save-core <OUTPUTFILENAME>
Frida¶
- Download the fridump tool (a bit outdated, but still works) from this link
mkdir memorydumpout python fridump.py -o memorydumpout -u <TARGETPROCESSNAME>
Unique ID¶
UDID is not accessible through the API since iOS 5. This is because it is used in other apple requests to identify the device.
identifierForVendor: A UUID that is the same for each application certificate on the same device. This ID can change when every app that is signed by the same key is removed from the device.
advertisingIdentifier: The same ID for every app on the device. This can be changed through a Reset All Content and Settings or a Reset Advertising Identifier.
Unique Device Identifier¶
- has not been used as an Identifier since iOS 5
- You can get this identifier from itunes
Get UDID from ioreg:
$ ioreg -p IOUSB -l | grep "USB Serial"
| "USB Serial Number" = "9e8ada44246cee813e2f8c1407520bf2f84849ec"
Get UDID from idevice Installer:
$ brew install ideviceinstaller
$ idevice_id -l
316f01bd160932d2bf2f95f1f142bc29b1c62dbc
Get UDID from system_profiler:
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
Get UDID from instruments:
instruments -s devices
Networking¶
Redirect traffic¶
Though /etc/hosts
127.0.0.1 localhost
::1 localhost
255.255.255.255 broadcasthost
192.168.1.6 example.com
Non-Jailbroken TCPdump¶
rvictl -s <UDID>
Starting device <UDID> [SUCCEEDED] with interface rvi0
Setting up Full Proxy of TCP¶
TODO:
Burp traffic through USB¶
Port Forward:
ssh -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -R 8080:localhost:8080 root@localhost -p 2222
Certificate Pinning¶
Using Standard Apple:
- connection: canAuthenticateAgainstProtectionSpace:
- connection: forAuthenticationChallenge
TrustKit:
AlamoFire:
- ServerTrustPolicy
AFNetworking:
- AFSecurityPolicy
Things to Grep For:
- NSURLSession
- CFStream
- AFNetworking
Inter Process Communication (IPC)¶
XPC Services¶
- Is managed by launchd to send information from one process to another.
- Uses the NSXPCConnection and XPC Services APIs
Classes to grep for:
- NSXPCConnection
- NSXPCInterface
- NSXPCListener
- NSXPCListenerEndpoint
Security Attributes:
- https://www.objc.io/issues/14-mac/xpc/#security-attributes-of-the-connection
Mach Ports¶
- Kernel level IPC messages
Things to grep for:
- mach_port_t
- mach_msg_*
- CFMachPort
- CFMessagePort
- NSMachPort
- NSMessagePort
NSFileCoordinator¶
- Used to share files with another app.
- Example Sharing photos with another app.
Things to grep for:
- NSFileCoordinator
URL Schema¶
URLs are contained in the Entitlements file.
- application:continueUserActivity:restorationHandler:
- openURL:options:completionHandler:
- application:openURL:options:
- application:will-FinishLaunchingWithOptions:
- application:didFinishLaunchingWithOptions:
- application:handleOpenURL:
- application:openURL:sourceApplication:annotation:
In Info.plist
- LSApplicationQueriesSchemes
Open URL with Frida:
function openURL(url) {
var UIApplication = ObjC.classes.UIApplication.sharedApplication();
var toOpen = ObjC.classes.NSURL.URLWithString_(url);
return UIApplication.openURL_(toOpen);
}
openURL("tel://234234234")
UIActivity Sharing¶
- Sharing data though specific mechanism like airdrop
Things to grep for:
- initWithActivityItems:applicationActivities:
- application:openURL:options:
- application:openURL:sourceApplication:annotation:
- excludedActivityTypes
App Extensions¶
These are located in the applicaiton IPA /var/containers/Bundle/Application/15E6A58F-1CA7-44A4-A9E0-6CA85B65FA35/ Telegram X.app/PlugIns
directory
[NSExtensionContext openURL:completionHandler:]
application:shouldAllowExtensionPointIdentifier:
NSExtensionContext - inputItems
WebView¶
Things to Grep for:
- WKWebView/UIWebView
- javaScriptEnabled
- JavaScriptCanOpenWindowsAutomatically
- hasOnlySecureContent
- loadHTMLString:baseURL:
- loadData:MIMEType:textEncodingName:baseURL:
- pathForResource:ofType:
- URLForResource:withExtension:
- loadRequest:
- loadFileURL:allowingReadAccessToURL:
- SFSafariViewController
- WKScriptMessageHandler
Log Files¶
Read Log Files on Device:
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
Reading Log Files from Computer:
idevicesyslog > app_name_$(date +%Y-%m-%d).log
WhiteBox¶
Check for these functions
- NSLog
- NSAssert
- NSCAssert
- fprintf
Backup¶
You can use the NSURLIsExcludedFromBackupKey
and CFURLIsExcludedFromBackupKey
file system properties to exclude files and directories from backups.
ObjC Example:
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
NSURL* URL= [NSURL fileURLWithPath: filePathString];
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
}
return success;
}
Swift Example:
enum ExcludeFileError: Error {
case fileDoesNotExist
case error(String)
}
func excludeFileFromBackup(filePath: URL) -> Result<Bool, ExcludeFileError> {
var file = filePath
do {
if FileManager.default.fileExists(atPath: file.path) {
var res = URLResourceValues()
res.isExcludedFromBackup = true
try file.setResourceValues(res)
return .success(true)
} else {
return .failure(.fileDoesNotExist)
}
} catch {
return .failure(.error("Error excluding \(file.lastPathComponent) from backup \(error)"))
}
}
Backing Up the iPhone¶
- Setting up password is not Mandatory????
Setting a Backup Password (Optional):
>>> idevicebackup2 -i encryption on
Started "com.apple.mobilebackup2" service on port 49439.
Negotiated Protocol Version 2.1
Enter new backup password: *********
Enter new backup password (repeat): *********
Backup encryption has been enabled successfully.
Backing up the Device:
idevicebackup2 -u 70a58077f305c2a6e64f5eb74660a8619cfda34e --debug -i backup --full .
Backup directory is "."
Clipboard¶
iOS < 9 malicious apps can retrieve clipboard information when backgrounded using [UIPasteboard generalPasteboard].string
. iOS >= 9 can only retrieve this information when in the foreground.
There are two types of Pasteboards. A System and a TeamID pasteboard.
Things to grep for:
- generalPasteboard
- pasteboardWithName:create:
- pasteboardWithUniqueName
- removePasteboardWithName:
- setItems:options:
- UIPasteboardOptionLocalOnly
- UIPasteboardOptionExpirationDate
- setPersistent:
Keyboard¶
By default iOS caches keyboard data and stores it in /private/var/mobile/Library/Keyboard/dynamic-text.dat
.
This can be disabled using the textObject.autocorrectionType = UITextAutocorrectionTypeNo;
or the textObject.secureTextEntry = YES;
flag.
Non Jailbroken Devices¶
Go to another app, see enter a partial match to some sensitive data and if a completion is offered.
Screenshots¶
iOS takes a screenshot when the application is backgrounded so it can show its self on the application switching screen. For sensitive screens the application should put a screen overlay to prevent sensitive information from leaking to another application.
The screenshots are located in the /var/mobile/Containers/Data/Application/$APP_ID/Library/Caches/Snapshots/
folder.
Screen Overlay Code:
@property (UIImageView *)backgroundImage;
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
[self.window addSubview:myBanner];
}