The protection of sensitive data, such as authentication tokens or private information, is a key focus in mobile security. In this chapter, you will learn about the APIs iOS offers for local data storage, as well as best practices for using them.
Note that "sensitive data" need to be identified in the context of each specific app. Data classification is described in detail in the chapter "Testing Processes and Techniques".
As little sensitive data as possible should be saved on permanent local storage. However, in most practical scenarios, at least some type of user-related data needs to be stored. Fortunately, iOS offers secure storage APIs which allow developers to make use of the crypto hardware available in every iOS device. Assuming that these APIs are used correctly, key data and files can be secured using hardware-backed 256 bit AES encryption.
App developers can leverage the iOS Data Protection APIs to implement fine-grained access controls for user data stored in flash memory. The API is built on top of the secure enclave, a coprocessor that provides cryptographic operations for data protection key management. A device-specific hardware key - the device UID - is embedded into the secure enclave, ensuring the integrity of data protection even if the operating system kernel is compromised.
The data protection architecture is based on a hierarchy of keys. The UID and the user passcode key, which is derived from the user's passphrase using the PBKDF2 algorithm, sits on the top of this hierarchy. Together, they can be used to "unlock" so-called class keys which are associated with different device states (e.g. device is locked/unlocked).
Every file stored in the iOS file system is encrypted with its own individual per-file key, which is contained in the file metadata. The metadata is encrypted with the file system key and wrapped with one of the class keys, depending on the protection class selected by the app when creating the file.
iOS Data Protection Key Hierarchy
Files can be assigned one of four protection classes:
-
Complete Protection (NSFileProtectionComplete): This class key is protected with a key derived from the user passcode and the device UID. It is wiped from memory shortly after the device is locked, making the data inaccessible until the user unlocks the device.
-
Protected Unless Open (NSFileProtectionCompleteUnlessOpen): Behaves 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 is implemented using asymmetric elliptic curve cryptography.
-
Protected Until First User Authentication (NSFileProtectionCompleteUntilFirstUserAuthentication): The file can be accessed from the moment the user unlocks the device for the first time after booting. It can be accessed even if the user subsequently locks the device.
-
No Protection (NSFileProtectionNone): This class key is protected only with the UID and is kept in Effaceable Storage. This protection class exists to enable fast remote wipe: Deleting the class key immediately 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 only happen on the device itself, and requires the correct passcode to be entered.
Since iOS 7, the default data protection class is "Protected Until First User Authentication".
The iOS Keychain is used to securely store short, sensitive bits of data, such as encryption keys and session tokens. It is implemented as a SQLite database that can be accessed only through Keychain APIs. The Keychain database is encrypted using the device Key and the user PIN/password (if one has been set by the user).
By default, each app can only access the Keychain created by itself. Access can however be shared between apps signed by the same developer by using the access groups feature in the attribute kSecAttrAccessGroup
. Access to the Keychain is managed by the securityd
daemon, which grants access based on the app's Keychain-access-groups
, application-identifier
and application-group
entitlements.
The KeyChain API consists of the following main operations with self-explanatory names:
SecItemAdd
SecItemUpdate
SecItemCopyMatching
SecItemDelete
Keychain data is protected using a class structure similar to the one used for file encryption. Items added to the Keychain are encoded as a binary plist and encrypted using a 128 bit AES per-item key. Note that larger blobs of data are not meant to be saved directly in the Keychain - that's what the Data Protection API is for. Data protection is activated by setting the kSecAttrAccessible
attribute in the SecItemAdd
or SecItemUpdate
call. The following Data Protection classes are available:
kSecAttrAccessibleAfterFirstUnlock
: The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user.kSecAttrAccessibleAlways
: The data in the keychain item can always be accessed regardless of whether the device is locked.kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
: The data in the keychain can only be accessed when the device is unlocked. Only available if a passcode is set on the device. The data will not be included in an iCloud or iTunes backup.kSecAttrAccessibleAlwaysThisDeviceOnly
: The data in the keychain item can always be accessed regardless of whether the device is locked. The data will not be included in an iCloud or iTunes backup.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 will not be included in an iCloud or iTunes backup.
Next to the Data Protection classes, there are AccessControlFlags
which define with which mechanism one can authenticate to unlock the key(SecAccessControlCreateFlags
):
kSecAccessControlDevicePasscode
: only access the item using a passcode.kSecAccessControlTouchIDAny
: access the item using one of your fingerprints registered to TouchID. Adding or removing a fingerprint will not invalidate the item.kSecAccessControlTouchIDCurrentSet
: access the item using one of your fingerprints registered to TouchID. Adding or removing a fingerprint will invalidate the item.kSecAccessControlUserPresence
: access the item using either one of the registered fingerprint (using TouchID) or fallback to the PassCode.
Please note that keys secured by TouchID (using kSecAccessControlTouchIDCurrentSet
or kSecAccessControlTouchIDAny
) are protected by the Secure Enclave: the keychain only holds a token, but not the actual key. The key resides in the Secure Enclave.
Next, from iOS 9 onward, you can do ECC based signing operations in the Secure Enclave. In that case the private key as well as the cryptographic operations reside within the Secure Enclave. See the remediation chapter for more info on creating the ECC keys. iOS 9 only supports ECC with length of 256 bits. Furthermore, you still need to store the public key in the Keychain, as that cannot be stored in the Secure Enclave.
Next, you can use the kSecAttrKeyType
to instruct what type of algorithm you want to use this key with upon creation of the key.
When having access to the source code of the iOS app, try to spot sensitive data that is saved and processed throughout the app. This includes in general passwords, secret keys, and personally identifiable information (PII), but might as well also include other data identified as sensitive through industry regulations, laws or internal policies. Look for instances where this data is saved using any of the local storage APIs listed below. Make sure that sensitive data is never stored without appropriate protection. For example, authentication tokens should not be saved in NSUserDefaults without additional encryption. In any case, the encryption must be implemented such that the secret key is stored in the Keychain using secure settings, ideally kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
.
Furthermore, make sure that the AccessControlFlags
are set appropriately according to the security policy for the given keys in the Keychain.
When looking for instances of insecure data storage in an iOS app you should consider the following possible means of storing data.
-
Core Data
: Is a framework that you use to manage the model layer of objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence. Core Data operates on a sqlite database at lower level. -
sqlite3
: Thelibsqlite3.dylib
library is required to be added in an application. This library is a C++ wrapper that provides the API to the SQLite commands.
The Realm Objective-C and the Realm Swift are not supplied by Apple, but still worth noting here. They either store everything unencrypted, unless the configuration has encryption enabled.
Couchbase Lite is an embedded lightweight, document-oriented (NoSQL), syncable database engine. It compiles natively for iOS and Mac OS.
YapDatabase is comprised of 2 main features:
- A collection/key/value store built atop sqlite for iOS & Mac (the foundation).
- A plugin architecture that provides for advanced functionality such as Views, Secondary Indexes, Full Text Search, etc.
The NSUserDefaults
class provides a programmatic interface for interacting with the default system. The default system allows an application to customize its behavior to match a user’s preferences. Data saved by NSUserDefaults can be viewed from the application bundle. It also stores data in a plist file, but it's meant for smaller amounts of data.
NSData
: Creates static data objects and NSMutableData creates dynamic data objects. NSData and NSMutableData are typically used for data storage and are also useful in distributed objects applications, where data contained in data objects can be copied or moved between applications. Methods used to write NSData objects:NSDataWritingWithoutOverwriting
NSDataWritingFileProtectionNone
NSDataWritingFileProtectionComplete
NSDataWritingFileProtectionCompleteUnlessOpen
NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication
writeToFile
": Stores data as part of the NSData classNSSearchPathForDirectoriesInDomains, NSTemporaryDirectory
: Are used to manage file paths.- The
NSFileManager
object lets you examine the contents of the file system and make changes to it. A way to create a file and write to it can be done throughcreateFileAtPath
.
A way to identify if sensitive information like credentials and keys are stored insecurely and without leveraging the native functions from iOS is to analyze the app data directory. It is important to trigger as much app functionality as possible before the data is analyzed, as the app might only store system credentials when specific functionality is triggered by the user. A static analysis can then be performed for the data dump based on generic keywords and app specific data.
The following steps can be used on a jailbroken device to identify how the application stores data locally on the iOS device.
- Proceed to trigger functionality that stores potential sensitive data.
- Connect to the iOS device and browse to the following directory (this is applicable to iOS version 8.0 and higher):
/var/mobile/Containers/Data/Application/$APP_ID/
- Perform a grep command of the data that you have stored, such as:
grep -iRn "USERID"
. - If the sensitive data is being stored in plaintext, it fails this test.
It is also possible to analyze the app data directory on a non-jailbroken iOS device using third party applications such as iMazing.
- Proceed to trigger functionality that stores potential sensitive data.
- Connect the iOS device to your workstation and launch the iMazing application.
- Select "Apps" and right-click on the desired iOS application, select "Extract App".
- Browse to the output directory and locate the $APP_NAME.imazingapp. Rename it to $APP_NAME.zip.
- Unpack the renamed .zip file and the application data can now be analyzed.
Important filesystem locations are:
- AppName.app
- The app’s bundle, contains the app and all of its resources
- Visible to users but users cannot write to this directory
- Content in this directory is not backed up
- Documents/
- Use this directory to store user-generated content
- Visible to users and users can write to this directory
- Content in this directory is being backed up
- App can disable paths by setting
NSURLIsExcludedFromBackupKey
- Library/
- This is the top-level directory for any files that are not user data files
- iOS apps commonly use the
Application Support
andCaches
subdirectories, but you can create custom subdirectories
- Library/Caches/
- Semi-persistent cached files
- Not visible to users and users cannot write to this directory
- Content in this directory is not backed up
- OS may delete the files automatically when app is not running (e.g. storage space running low)
- Library/Application Support/
- Persistent files necessary to run the app
- Not visible to users and users cannot write to this directory
- Content in this directory is being backed up
- App can disable paths by setting
NSURLIsExcludedFromBackupKey
- Library/Preferences/
- Used for storing properties, objects that can persist even after an application restart.
- Information is saved unencrypted inside the application sandbox in a plist file with the name [BUNDLE_ID].plist.
- All the key/value pairs stored using NSUserDefaults can be found in this file.
- tmp/
- Use this directory to write temporary files that do not need to persist between launches of your app
- Non-persistent cached files
- Not visible to the user
- Content in this directory is not backed up
- OS may delete the files automatically when app is not running (e.g. storage space running low).
For a more detailed analysis, use an API monitoring tool such as IntroSpy to instrument the app.
If necessary during dynamic analysis, the contents of the Keychain can be dumped using keychain dumper as described in the chapter "Basic Security Testing on iOS".
The keychain file is located at:
/private/var/Keychains/keychain-2.db
Hardware-backed storage mechanisms must be used for storing sensitive data. Permitted options for storing sensitive data are:
- Storing the data in the keychain with the
kSecAttrAccessibleWhenUnlocked
attribute. - Encrypting the data using standard crypto APIs before storing it, and storing the encryption key in the keychain.
- Another option is to use the encryption support, such as Realm provides.
// 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)")
}
- Creating a file with the
NSFileProtectionComplete
attribute.
The following example shows how to create a securely encrypted file using the createFileAtPath
method:
[[NSFileManager defaultManager] createFileAtPath:[self filePath]
contents:[@"secret text" dataUsingEncoding:NSUTF8StringEncoding]
attributes:[NSDictionary dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey]];
A generic example for using the KeyChain to store, update or delete data can be found in the official Apple documentation.
A sample for using TouchID and passcode protected keys can be found in the official Apple documentation.
Here is a sample in Swift with which you can use to create keys (notice the kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave
: here you instruct that we want to use the Secure Enclave directly):
// private key parameters
let privateKeyParams: [String: AnyObject] = [
kSecAttrLabel as String: "privateLabel",
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: "applicationTag"
]
// public key parameters
let publicKeyParams: [String: AnyObject] = [
kSecAttrLabel as String: "publicLabel",
kSecAttrIsPermanent as String: false,
kSecAttrApplicationTag as String: "applicationTag"
]
// global parameters
let parameters: [String: AnyObject] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPublicKeyAttrs as String: publicKeyParams,
kSecPrivateKeyAttrs as String: privateKeyParams
]
var pubKey, privKey: SecKeyRef?
let status = SecKeyGeneratePair(parameters, &pubKey, &privKey)
-- [TODO: add key generation for RSA encryption] --
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.1: "System credential storage facilities are used appropriately to store sensitive data, such as user credentials or cryptographic keys."
- CWE-311 - Missing Encryption of Sensitive Data
- CWE-312 - Cleartext Storage of Sensitive Information
- CWE-522 - Insufficiently Protected Credentials
- CWE-922 - Insecure Storage of Sensitive Information
There are many legit reasons to create log files on a mobile device, for example to keep track of crashes or errors that are stored locally when being offline and being sent to the apps developer once online again or for usage statistics. However, logging sensitive data such as credit card number and session IDs might expose the data to attackers or malicious applications. Log files can be created in various ways. The following list shows the mechanisms that are available on iOS:
- NSLog Method
- printf-like function
- NSAssert-like function
- Macro
Check the app source code for usage of predefined and/or custom logging statements by using the following keywords:
- For predefined and built-in functions:
- NSLog
- NSAssert
- NSCAssert
- fprintf
- For custom functions:
- Logging
- Logfile
Proceed to a page on the iOS application that contains input fields which prompt users for their sensitive information. Two different methods are applicable to check for sensitive data in log files:
- Connect to the iOS device and execute the following command:
tail -f /var/log/syslog
- Connect your iOS device via USB and launch Xcode. Navigate to Windows > Devices, select your device and the respective application.
Proceed to complete the input fields prompt and if the sensitive data are displayed in the output of the above command, it fails this test.
Use a define to enable NSLog statements for development and debugging, and disable these before shipping the software. This can be done by putting the following code into the appropriate PREFIX_HEADER (*.pch) file:
#ifdef DEBUG
# define NSLog (...) NSLog(__VA_ARGS__)
#else
# define NSLog (...)
#endif
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.2: "No sensitive data is written to application logs."
- CWE-117: Improper Output Neutralization for Logs
- CWE-532: Information Exposure Through Log Files
- CWE-534: Information Exposure Through Debug Log Files
- Xcode
Different 3rd party services are available that can be embedded into the app to implement different features. These features can vary from tracker services to monitor the user behavior within the app, selling banner advertisements or to create a better user experience. Interacting with these services abstracts the complexity and neediness to implement the functionality on its own and to reinvent the wheel.
The downside is that a developer doesn’t know in detail what code is executed via 3rd party libraries and therefore giving up visibility. Consequently it should be ensured that not more information as needed is sent to the service and that no sensitive information is disclosed.
3rd party services are mostly implemented in two ways:
- By using a standalone library.
- By using a full SDK.
API calls and/or functions provided through the 3rd party library should be reviewed on a source code level to identify if they are used accordingly to best practices.
All requests made to external services should be analyzed if any sensitive information is embedded into them. By using an interception proxy, we can try to investigate the traffic from the app to the 3rd party endpoints. When using the app all requests that are not going directly to the server where the main function is hosted should be checked, if any sensitive information is sent to a 3rd party. This could be for example PII (Personal Identifiable Information) in a tracker or ad service.
All data that is sent to 3rd Party services should be anonymized, so no PII data is available that would allow the 3rd party to identify the user account. Also all other data, like IDs in an application that can be mapped to a user account or session should not be sent to a third party.
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.3: "No sensitive data is shared with third parties unless it is a necessary part of the architecture."
- CWE-359 "Exposure of Private Information ('Privacy Violation')"
- OWASP ZAP
- Burp Suite Professional
In order to simplify keyboard input by providing autocorrection, predicative input, spell checking, etc., most of keyboard input by default is cached in /private/var/mobile/Library/Keyboard/dynamic-text.dat
.
This behavior is achieved by means of UITextInputTraits protocol, which is adopted by UITextField, UITextView and UISearchBar. Keyboard caching is influenced by following properties:
var autocorrectionType: UITextAutocorrectionType
determines whether autocorrection is enabled or disabled during typing. With autocorrection enabled, the text object tracks unknown words and suggests a more suitable replacement candidate to the user, replacing the typed text automatically unless the user explicitly overrides the action. The default value for this property isUITextAutocorrectionTypeDefault
, which for most input methods results in autocorrection being enabled.var secureTextEntry: BOOL
identifies whether text copying and text caching should be disabled and in case of UITextField hides the text being entered. This property is set toNO
by default.
-
Search through the source code provided to look for similar implementations, like the following:
textObject.autocorrectionType = UITextAutocorrectionTypeNo; textObject.secureTextEntry = YES;
-
Open xib and storyboard files in the
Interface Builder
of Xcode and verify states ofSecure Text Entry
andCorrection
inAttributes Inspector
for appropriate objects.
-
Reset your iOS device keyboard cache by going through: Settings > General > Reset > Reset Keyboard Dictionary
-
Proceed to use the application's functionalities. Identify the functions which allow users to enter sensitive data.
-
Dump the keyboard cache file dynamic-text.dat at the following directory (Might be different in iOS below 8.0):
/private/var/mobile/Library/Keyboard/
-
Look for sensitive data such as username, passwords, email addresses, credit card numbers, etc. If the sensitive data can be obtained through the keyboard cache file, it fails this test.
The application must ensure that data typed into text fields which contains sensitive information are not cached. This can be achieved by disabling the feature programmatically by using the textObject.autocorrectionType = UITextAutocorrectionTypeNo
directive in the desired UITextFields, UITextViews and UISearchBars. For data that should be masked such as PIN and passwords, set the textObject.secureTextEntry
to YES
.
UITextField *textField = [ [ UITextField alloc ] initWithFrame: frame ];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.4: "The keyboard cache is disabled on text inputs that process sensitive data."
- CWE-524: Information Exposure Through Caching
When keying in data into input fields, the clipboard can be used to copy data in. The clipboard is accessible systemwide and therefore shared between the apps. This feature can be misused by malicious apps in order to get sensitive data.
Before iOS 9, a malicious app might monitor the pasteboard in the background while periodically retrieving [UIPasteboard generalPasteboard].string
. As of iOS 9, the access to the pasteboard content is only allowed to apps in the foreground.
Search through the source code provided to look for any implemented subclass of UITextField
.
@interface name_of_sub_class : UITextField
action == @select(cut:)
action == @select(copy:)
Proceed to a view in the app that has input fields which prompt the user for sensitive information such as username, password, credit card number, etc. Enter some values and double tap on the input field. If the "Select", "Select All", and "Paste" option shows up, proceed to tap on the "Select", or "Select All" option, it should allow you to "Cut", "Copy", "Paste", or "Define". The "Cut" and "Copy" option should be disabled for sensitive input fields, since it will be possible to retrieve the value by pasting it. If the sensitive input fields allow you to "Cut" or "Copy" the values, it fails this test.
Possible remediation method to disable clipboard on iOS:
@interface NoSelectTextField : UITextField
@end
@implementation NoSelectTextField
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(paste:) ||
action == @selector(cut:) ||
action == @selector(copy:) ||
action == @selector(select:) ||
action == @selector(selectAll:) ||
action == @selector(delete:) ||
action == @selector(makeTextWritingDirectionLeftToRight:) ||
action == @selector(makeTextWritingDirectionRightToLeft:) ||
action == @selector(toggleBoldface:) ||
action == @selector(toggleItalics:) ||
action == @selector(toggleUnderline:)
) {
return NO;
}
return [super canPerformAction:action withSender:sender];
}
@end
To clear the pasteboard with UIPasteboardNameGeneral:
UIPasteboard *pb = [UIPasteboard generalPasteboard];
[pb setValue:@"" forPasteboardType:UIPasteboardNameGeneral];
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.5: "The clipboard is deactivated on text fields that may contain sensitive data."
- CWE-200: Information Exposure
Inter Process Communication (IPC) is a method that allows processes to send each other messages and data. In case two processes need to communicate with each other, different methods are available to implement IPC on iOS:
- XPC Services: XPC is a structured, asynchronous interprocess communication library which provides basic interprocess communication and is managed by
launchd
. It runs with the most restricted environment possible: sandboxed with minimal file system access, network access, and no root privilege escalation. There are two different APIs, when working with XPC Services:- NSXPCConnection API and
- XPC Services API
- Mach Ports: All IPC communication ultimately relies on the Mach Kernel API. Mach Ports allow for local communication (on the same device) only. They can either be implemented natively or by using Core Foundation (CFMachPort) and Foundation (NSMachPort) wrappers.
- NSFileCoordinator: The class NSFileCoordinator can be used to manage and exchange data between apps through files that are accessible on the local file system for different processes.
The following section summarizes different keywords that you should look for in order to identify IPC implementations within iOS source code.
Several classes might be used when implementing the NSXPCConnection API:
- NSXPCConnection
- NSXPCInterface
- NSXPCListener
- NSXPCListenerEndpoint
Several security attributes for the connection can be set and should be verified.
For the XPC Services API, which are C-based, the availability of the following two files in the Xcode project should be checked:
- xpc.h
- connection.h
Keywords to look for in low-level implementations:
- mach_port_t
- mach_msg_*
Keywords to look for in high-level implementations (Core Foundation and Foundation wrappers):
- CFMachPort
- CFMessagePort
- NSMachPort
- NSMessagePort
Keywords to look for:
- NSFileCoordinator
IPC mechanisms should be verified via static analysis in the iOS source code. At this point of time no tool is available on iOS to verify IPC usage.
XPC services is the most secure and flexible way when implementing IPC on iOS and should be used primarily.
NSFileCoordinator methods run synchronously, so your code will block until they complete. That's convenient since you don't have to wait for an asynchronous block callback, but it obviously also means that they block the current thread.
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.6: "No sensitive data is exposed via IPC mechanisms."
- CWE-634 - Weaknesses that Affect System Processes
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.7: "No sensitive data, such as passwords or pins, is exposed through the user interface."
- CWE
Like other modern mobile operating systems iOS offers auto-backup features that create copies of the data on the device. On iOS, backups can be made either through iTunes, or the cloud using the iCloud backup feature. In both cases, the backup includes nearly all data stored on the device, except some highly sensitive things like Apple Pay information and TouchID settings.
Since iOS backs up installed apps and their data, an obvious concern is whether sensitive user data stored by the app might unintentionally leak through the backup. The answer to this question is "yes" - but only if the app insecurely stores sensitive data in the first place.
When a user backs up their iPhone, the keychain data is backed up as well, but the secrets in the keychain remain encrypted. The class keys needed to decrypt the keychain data that are not included in the backup. To restore the keychain data, the backup must be restored to a device, and the device must be unlocked with the same passcode.
Keychain items with the kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
attribute set can be decrypted only if the backup is restored to the same device. An evildoer trying to extract this Keychain data from the backup would be unable to decrypt it without access to the crypto hardware inside the originating device.
The takeaway: As long as sensitive data is handled as recommended earlier in this chapter (stored in the Keychain, or encrypted with a key locked inside the Keychain), backups aren't an issue.
The NSURLIsExcludedFromBackupKey and CFURLIsExcludedFromBackupKey file system properties can be used to exclude files and directories from backups. Apps that need to exclude a large number of files can exclude them by creating their own sub-directory and marking that directory as excluded. Apps should create their own directories for exclusion, rather than excluding the system defined directories.
Either of these APIs is preferred over the older, deprecated approach of directly setting an extended attribute. All apps running on iOS 5.1 and later should use these APIs to exclude data from backups.
The following is a sample code for excluding a file from backup on iOS 5.1 and later (Objective-C):
- (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;
}
The following is a sample code for excluding a file from backup on iOS 5.1 and later (Swift):
func addSkipBackupAttributeToItemAtURL(filePath:String) -> Bool
{
let URL:NSURL = NSURL.fileURLWithPath(filePath)
assert(NSFileManager.defaultManager().fileExistsAtPath(filePath), "File \(filePath) does not exist")
var success: Bool
do {
try URL.setResourceValue(true, forKey:NSURLIsExcludedFromBackupKey)
success = true
} catch let error as NSError {
success = false
print("Error excluding \(URL.lastPathComponent) from backup \(error)");
}
return success
}
Review the iOS mobile application source code to see if data is backed up unencrypted. -- TODO
After the app data has been backed up, review the data content of the backup files and folders. Specifically, the following directories should be reviewed to check if they contain any sensitive data:
- Documents/
- Library/Caches/
- Library/Application Support/
- tmp/
Refer to the overview of this section to read up more on the purpose of each of the mentioned directories and the type of information they store.
In performing an iTunes backup of a device on which a particular mobile application has been installed, the backup will include all subdirectories (except for the Library/Caches/
subdirectory) and files contained within that app's private directory on the device's file system.
As such, avoid storing any sensitive data in plaintext within any of the files or folders within the app's private directory or subdirectories.
While all the files in Documents/
and Library/Application Support/
are always being backed up by default, it is possible to exclude files from the backup by calling [NSURL setResourceValue:forKey:error:]
using the NSURLIsExcludedFromBackupKey
key.
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.8: "No sensitive data is included in backups generated by the mobile operating system."
- CWE-200: Information Exposure
- CWE-538: File and Directory Information Exposure
Manufacturers want to provide device users an aesthetically pleasing effect when an application is entered or exited, hence they introduced the concept of saving a screenshot when the application goes into the background. This feature could potentially pose a security risk for an application, as the screenshot containing sensitive information (e.g. a screenshot of an email or corporate documents) is written to local storage, where it can be recovered either by a rogue application on a jailbroken device, or by someone who steals the device.
While analyzing the source code, look for the fields or screens where sensitive data is involved. Identify if the application sanitize the screen before being backgrounded by using UIImageView.
Proceed to a page on the application which displays sensitive information such as username, email address, account details, etc. Background the application by hitting the Home button on your iOS device. Connect to the iOS device and proceed to the following directory (might be different in iOS below 8.0):
/var/mobile/Containers/Data/Application/$APP_ID/Library/Caches/Snapshots/
If the application caches the sensitive information page as a screenshot, it fails this test.
It is highly recommended to have a default screenshot that will be cached whenever the application enters the background.
Possible remediation method that will set a default screenshot:
@property (UIImageView *)backgroundImage;
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
[self.window addSubview:myBanner];
}
This will cause the background image to be set to the "overlayImage.png" instead whenever the application is being backgrounded. It will prevent sensitive data leaks as the "overlayImage.png" will always override the current view.
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.9: "The app removes sensitive data from views when backgrounded."
- CWE-200 - Information Exposure
Analyzing the memory can help to identify the root cause of different problems, like for example why an application is crashing, but can also be used to identify sensitive data. This section describes how to check for sensitive data and disclosure of data in general within the process memory.
To be able to investigate the memory of an application a memory dump needs to be created first or the memory needs to be viewed with real-time updates. This is also already the problem, as the application only stores certain information in memory if certain functions are triggered within the application. Memory investigation can of course be executed randomly in every stage of the application, but it is much more beneficial to understand first what the mobile app is doing and what kind of functionalities it offers and also make a deep dive into the (decompiled) source code before making any memory analysis. Once sensitive functions are identified, like decryption of data, the investigation of a memory dump might be beneficial in order to identify sensitive data like a key or the decrypted information itself.
-- ToDo
In order to dump the memory of an iOS app, several different approaches and tools are available that are listed below.
It is possible to dump the process memory of the app with objection and Fridump on a non-jailbroken device. To take advantage of this the iOS app need to be repackaged with FridaGadget.dylib and re-signed. A detailed explanation on how to do this is in the section "Dynamic Analysis on Non-Jailbroken Devices" in the chapter "Basic Security Testing".
With objection it is possible to dump all memory of the running processes on the iPhone.
(virtual-python3) ➜ objection explore
_ _ _ _
___| |_ |_|___ ___| |_|_|___ ___
| . | . | | | -_| _| _| | . | |
|___|___|_| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v0.1.0
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
iPhone on (iPhone: 10.3.1) [usb] # memory dump all /Users/foo/memory_iOS/memory
Dumping 768.0 KiB from base: 0x1ad200000 [####################################] 100%
Memory dumped to file: /Users/foo/memory_iOS/memory
Afterwards the command strings
can be executed on the dump to extract the strings.
$ strings memory > strings.txt
Open strings.txt in your favourite editor and dig through it to identify sensitive information.
The loaded modules of the current process can also be shown.
iPhone on (iPhone: 10.3.1) [usb] # memory list modules
Name Base Size Path
-------------------------------- ----------- ------------------- ---------------------------------------------------------------------------------
foobar 0x1000d0000 11010048 (10.5 MiB) /var/containers/Bundle/Application/D1FDA1C6-D161-44D0-BA5D-60F73BB18B75/...
FridaGadget.dylib 0x100ec8000 3883008 (3.7 MiB) /var/containers/Bundle/Application/D1FDA1C6-D161-44D0-BA5D-60F73BB18B75/...
libsqlite3.dylib 0x187290000 1118208 (1.1 MiB) /usr/lib/libsqlite3.dylib
libSystem.B.dylib 0x18577c000 8192 (8.0 KiB) /usr/lib/libSystem.B.dylib
libcache.dylib 0x185bd2000 20480 (20.0 KiB) /usr/lib/system/libcache.dylib
libsystem_pthread.dylib 0x185e5a000 40960 (40.0 KiB) /usr/lib/system/libsystem_pthread.dylib
libsystem_kernel.dylib 0x185d76000 151552 (148.0 KiB) /usr/lib/system/libsystem_kernel.dylib
libsystem_platform.dylib 0x185e53000 28672 (28.0 KiB) /usr/lib/system/libsystem_platform.dylib
libdyld.dylib 0x185c81000 20480 (20.0 KiB) /usr/lib/system/libdyld.dylib
The original version of Fridump is not maintained anymore and is only working with Python2. Frida is nowadays highly suggesting to use the latest Python 3.x and therefore Fridump is not working out of the box.
If you are getting the following error message, even though your iOS device is connected via USB, you should checkout Fridump with the fix for Python 3.
➜ fridump_orig git:(master) ✗ python fridump.py -u Gadget
______ _ _
| ___| (_) | |
| |_ _ __ _ __| |_ _ _ __ ___ _ __
| _| '__| |/ _` | | | | '_ ` _ \| '_ \
| | | | | | (_| | |_| | | | | | | |_) |
\_| |_| |_|\__,_|\__,_|_| |_| |_| .__/
| |
|_|
Can't connect to App. Have you connected the device?
Once Fridump is working, you need to get the Name of the app you want to dump, which can be done by using frida-ps
. Afterwards you just specify the app name in fridump.
➜ fridump git:(master) ✗ frida-ps -U
PID Name
---- ------
1026 Gadget
➜ fridump git:(master) python3 fridump.py -u Gadget -s
______ _ _
| ___| (_) | |
| |_ _ __ _ __| |_ _ _ __ ___ _ __
| _| '__| |/ _` | | | | '_ ` _ \| '_ \
| | | | | | (_| | |_| | | | | | | |_) |
\_| |_| |_|\__,_|\__,_|_| |_| |_| .__/
| |
|_|
Current Directory: /Users/foo/PentestTools/iOS/fridump
Output directory is set to: /Users/foo/PentestTools/iOS/fridump/dump
Creating directory...
Starting Memory dump...
Progress: [##################################################] 100.0% Complete
Running strings on all files:
Progress: [##################################################] 100.0% Complete
Finished! Press Ctrl+C
When you add the flag -s
all strings are extracted from the dumped raw memory files into the file strings.txt
and is stored in the directory dump
of Fridump.
-- ToDo
-- ToDo
- M1 - Improper Platform Usage
- M2 - Insecure Data Storage
- V2.10: "The app does not hold sensitive data in memory longer than necessary, and memory is cleared explicitly after use."
- CWE-316 - Cleartext Storage of Sensitive Information in Memory
- V2.11: "The app enforces a minimum device-access-security policy, such as requiring the user to set a device passcode."
- M1 - Improper Platform Usage
- N/A