0. First Thing First
本文章是 MDSec whitepaper的节选.
MDSec 在2012年的一个 Slide, 浓缩了 white paper的内容. 假如时间有限, 可以先阅读该 Slide.
不过white paper 的附录中有不少优质的参考资料, 同样值得一读.
0.1 Exploit Demo
Breaking secure Mobile Applications BSides - Slide, 其中介绍了一个 decrypt 加密了 db 的案例.
- RE apk 获知 app 用的是 sqlcipher 加密, IMEI作为 salt
- 依样画葫芦, 写一样的代码获取 key
- 利用 key 解密 db
Code signing is a runtime security feature of the platform that attempts to prevent unauthorised applications running on the device by validating the application signature each time it is executed. Additionally, applications may also only execute code signed by a valid, trusted signature.
For an application to be run on the device, it must first be signed by a trusted certificate. Developers can install trusted certificates on a device through a provisioning profile signed by Apple. The provisioning profile contains the embedded developer certificate and set of entitlements that the developer may grant to applications. In production applications, all code must be signed by Apple, this is performed during the AppStore submission process.
Exploit Mitigation Features
Address Space Layout Randomisation (ASLR) is a security feature that attempts to increase the complexity of vulnerability exploitation by randomising where data and code is mapped in a processes address space.
Applications can have ASLR applied in two different flavours, either partial ASLR or full ASLR depending on whether they have been compiled with support for Position Independent Execution (PIE).
- Full ASLR
- All the application memory regions are randomised and iOS will load a PIE enabled binary at a random address each time it is executed.
- Partial ASLR
- An application with partial ASLR will load the base binary at a fixed address and use a static location for the dynamic linker (dyld).
The most common of these techniques is memory revelation. This is where a separate vulnerability is used to leak or confirm memory layout to an attacker prior exploitation of a vulnerability that will yield arbitrary code execution.
In an attempt to further mitigate exploitation of native language vulnerabilities, iOS makes memory pages cannot be marked as writeable and executable at the same time.
As part of this policy, executable memory pages that are marked as writeable cannot also be later marked back to executable.
While non-executable memory alone can be trivially bypassed using Return Orientated Programming (ROP) based payloads, the complexity of exploitation is significantly increased when compounded with ASLR and Mandatory Code Signing.
iOS applications can look to add additional exploit mitigation at compile time through stack smashing protection. Stack canaries in particular introduce some protection against buffer overflows by placing a random, known value before the local variables. The stack canary is checked upon return of the function. If an overflow occurs and the canary is corrupted, the application is able to detect and protect against the overflow.
All third party applications on iOS run within a sandbox; this is a self-contained environment that isolates applications not only from other applications but also the operating system. While applications all run as the “mobile” operating system user, they are contained within a unique directory on the filesystem and separation is maintained by the XNU Sandbox kernel extension. The operations that can be performed in the sandbox are governed by the seatbelt profile. Third party applications are assigned the “container” profile which will generally limit file access to the application home directory, allow read access to media, read and write to the address book as well as unrestricted access to outbound network connections, with the exception of
launchd’s network sockets.
By default, all data on the iOS filesystem is encrypted using block-based encryption (AES) with the File System Key, which is stored on the flash. The filesystem is encrypted only at rest; when the device is turned on the hardware based crypto accelerator unlocks the filesystem.
In addition to the hardware encryption, individual files and keychain items can be encrypted using the Data Protection (DP) API that uses a key derived from the device passcode. Consequently, when the device is locked, content encrypted using the DP API will be inaccessible unless cached in memory. Third party applications wishing to encrypt sensitive data should employ the Data Protection API to do so. However consideration should be given for background processes how they will behave if the at-rest becomes unavailable due to the device becoming locked.
2. Blackbox assessment
Locating the Position Independent Executable
Position Independent Executable (PIE) is an exploit mitigation security feature that allows an application to take full advantage of ASLR.
In order for this to happen, the app must be compiled using the
–fPIE –pie flag; using XCode this can be enabled/disabled using the “Generate Position-Dependent Code” option from the compiler code generation build setting.
- Compiling the above application without PIE and running on the iPhone, we can see that despite system wide ASLR the main executable is loaded at a fixed address.
- Recompiling the same application with PIE, we can see the app now loads the main executable at a dynamic address.
Since iOS5, Compile with PIE by default.
Identifying the use of Stack Smashing Protection
Compile with flag -
When an app is compiled with stack smashing protection, a known value or “canary” is placed on the stack directly before the local variables to protect the saved base pointer, saved instruction pointer and function arguments.
From a black box perspective, the presence of stack canaries can be identified by examining the symbol table of the binary.
$ otool -I -v DummyApp | grep stack
Identifying the use of Automatic Reference Counting
Automatic Reference Counting (ARC) was introduced in iOS SDK version 5.0 to move the responsibility of memory management from the developer to the compiler. Consequently, ARC also offers some security benefits as it reduces the likelihood of developers introducing memory corruption (specifically object use- after-free and double free) vulnerabilities in to apps.
$ otool -I -v DummyApp-ARC | grep "_objc_release"
The symbols that highlight the presence of ARC are:
White box iOS App assessment, check if
Inspecting the binary
With a decrypted binary, there is a wealth of information in the
__OBJC segment that can be useful to a reverse engineer. The
__OBJC segment provides details on the internal classes, methods and variables used in the app; this information is particularly useful when looking to understand how the app functions, patching the app or hooking the app at runtime.
By identifying the methods, it could hook the methods and modified them at runtime.
Tool: MobileSubstrate, Frida, AppMon, Cycript
Example usage: Bypassing Jailbroken Detection
Defending the Binary
One of the most common approaches for defending the runtime is to integrity check classes for expected addresses or checksums, allowing an app to determine if the Objective-C runtime has been hooked or modified.
3. Auditing Insecure API usage
The following key touch points in an application should be reviewed when performing source code reviews of reviewing iOS applications.
Evaluating Transport Security
In order to prevent Man-in-the-Middle attacks, it is essential for iOS applications to prohibit the use of self-signed certificates. The default behaviour for the
NSURLRequest class is to reject self-signed certificates and raise an
NSURLErrorDomain exception. However, it is not uncommon to see developers override this behaviour to accept any certificate, frequently to allow the use of self-signed certificates deployed in pre-production environments. The certificate validation can be disabled for the requested domain using the
Abusing Protocol Handlers
Due to the restrictions imposed by the iOS sandbox, Inter-Process Communication (IPC) is generally prohibited. However, a simple form of IPC is supported by the API if the application registers a custom protocol handler.
There are many reasons why a developer might want to support IPC; some examples that we’ve seen in practice include determining the presence of other apps, allowing the app to be launched from Safari or passing data between apps.
There are two API methods commonly used to implement protocol handlers on iOS,
application:handleOpenURL, the latter now deprecated. The advantage of using the
openURL method is that it supports validation of the source application that instantiated the URL request.
Exploit Example: Skype iOS App registered the 'skype' protocol handler which could be initiate calls and chats.
An attack to perform a call without authorization using a malicious iframe.
The attack payload could be triggered from MobileSafari to launch the Skype app, which would perform the call as shown below:
Locating insecure storage
|No Protection||The file is not encrypted on the file-system.|
|Complete Protection||The file is encrypted on the file-system and inaccessible when the device is locked.|
|Complete UnlessOpen||The file is encrypted on the file-system and inaccessible while closed. When a device is unlocked an app can maintain an open handle to the file even after it is subsequently locked, however during this time the file will not be encrypted.|
|Complete Until First User Authentication||The file is encrypted on the file-system and inaccessible until the device is unlocked for the first time. This helps offer some protection against attacks that require a device reboot.|
For example, consider an application that needs to save some data to the file- system, but it does not require access to the file while the device is locked, such as an app that allows you to download documents and then later view them. As the app does not require access to the files when the device is locked, it can take advantage of the complete protection by setting the
Attacking the iOS Keychain
|kSecAttrAccessibleAlways||The keychain item is always accessible.|
|kSecAttrAccessibleWhenUnlocked||The keychain item is only accessible when the device is unlocked.|
|kSecAttrAccessibleAfterFirstUnlock||They keychain item is only accessible after the first unlock from boot. This helps offer some protection against attacks that require a device reboot.|
|kSecAttrAccessibleAlwaysThisDeviceOnly||The keychain item is always accessible but cannot be migrated to other devices.|
|kSecAttrAccessibleWhenUnlockedThisDeviceOnly||The keychain item is only accessible when the device is unlocked and may not be migrated to other devices.|
|kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly||The keychain item is accessible after the first unlock from boot and may not be migrated to other devices.|
Applications' access to keychain items is limited by the entitlements they are granted. The keychain uses application identifiers stored in the “keychain- access-group” entitlement of the provisioning profile for the app; a sample provisioning profile that allows keychain access only to the app’s keychain is shown overleaf:
<?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>application-identifier</key> <string>my.company.VulnerableiPhoneApp</string> <key>get-task-allow</key> <true/> <key>keychain-access-group</key> <array> <string>my.company.VulnerableiPhoneApp</string> </array> </dict> </plist>
Conducting XSS through UIWebView
Attacking XML Processors
iPhone SDK (NIN: This article was written years ago, while iOS 5 was the latest) provides two options for parsing XML:
- Denial of Service with nested entity
- XXE - External XML entity
While in most circumstances this has little impact as the data store is client-side, it is an exploitable condition if untrusted data supplied by a malicious user is retrieved from the server.
Attack: Path Traversal
Read files within the sandbox container.
To avoid the app being used to track a user’s movements, it is generally recommended that location information is not stored on the device. In addition to client-side logging, if the app passes coordinate information to a server, developers should ensure that if this information is logged, it is done so anonymously.
Logging in objective C is typically performed using the
NSLog method that causes a message to be sent to the Apple System Log. These console logs are not only accessible using the Xcode organiser application but by any app installed on the device, using the ASL library.
In some cases jailbreaking a device will cause NSLog output to be redirected to syslog.
If an application is open, it is possible that it can be sent in to the background by a change in state, such as the user pressing the Home button or from an incoming call. When an application is suspended in the background, iOS will take a “snapshot” of the app and store it in the application caches directory. When the application is reopened, the device will use the screenshot to create the appearance that the application loads instantly rather than the small amount of time it actually takes to reload the application and for it to become useable again.
4. Memory Corruption Issues
iOS apps are typically resilient to classic memory corruption issues such as buffer overflows if the developers rely on Objective-C to perform memory allocations as the developer cannot specify fixed sizes for buffers.
Consequently, for apps using ARC there is likely to be a significant reduction in the number of use-after-free issues as the developer no longer bears the responsibility for releasing or retaining objects.