CHAPTER 4
Identifying iOS Implementation Insecurities

Armed with the knowledge from Chapter 3, you are well equipped to understand the mechanisms for testing iOS applications. However, in addition to the various attack scenarios, you should consider a number of other things when developing or assessing an iOS application. Indeed, many weaknesses can arise as a consequence of using certain APIs in the iOS SDK. This chapter documents the avenues in which due to lack of awareness, developers can inadvertently expose their applications to risk through these API side effects. Where applicable, the chapter also details remedial action and ways to secure implementations.

Disclosing Personally Identifiable Information

Although the issue is not specific to iOS, handling personal data is a serious concern for mobile applications and one that should be considered during the design phase of an application and stringently investigated as part of any assessment. Any data that can be used to uniquely identify users, their habits, locations, actions, or the device should be treated with particular care. Such information may not strictly be considered personally identifiable information (PII), but it can be used to track the user, which can also be considered an infringement of privacy.

Typically, when you review how a mobile application handles personal data, you should consider the following attack vectors:

This section details some of the types of personal or privacy-related data that you may encounter when reviewing an iOS application.

Handling Device Identifiers

Every iOS device has a 40-character-long hex value, known as the unique device identifier (UDID), that uniquely identifies the device. You can find the UDID for your device by clicking on the Serial Number option under the device Summary tab in iTunes.

Prior to iOS 6, third-party applications could access the UDID using the iOS public APIs. This lead to it not only being used to track users for marketing and advertising purposes, but also in some cases for nefarious reasons. Apple responded to this abuse by revoking access to the UDID for third-party applications.

However, legitimate reasons can sometimes exist for an application to identify a user or device, and some users may be happy to receive advertisements. At present there are two methods of identifying a device, and you should consider how they are used or protected when assessing an application:

  • AdSupport framework—Introduced in iOS 6 specifically for applications that use advertisements, this framework exposes the advertisingIdentifier property (see https://developer.apple.com/LIBRARY/ios/documentation/AdSupport/Reference/ASIdentifierManager_Ref/index.html#//apple_ref/occ/instp/ASIdentifierManager/advertisingIdentifier). This property returns a unique identifier that is static across all applications but can be manually reset by the user via the Settings ➢ Privacy ➢ Advertising ➢ Reset Advertising Identifier setting. The identifier will also be reset automatically if you reset or erase your device. The use of this identifier is also subject to certain restrictions that are dependent upon the value of the Limit Ad Tracking setting that is found in the Advertising settings category of the device. If the flag is enabled, applications should use the identifier only for frequency capping, conversion events, estimating the number of unique users, security and fraud detection, and debugging. However, enforcing this is difficult because if the data is aggregated and processed on the server side, Apple has no way to concretely ascertain how it is being used, and so misuse of this property can raise privacy concerns.
  • UIDevice class—An alternate method of identifying the device is the identifierForVendor property (see https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/index.html#//apple_ref/doc/uid/TP40006902-CH3-SW11) in the UIDevice class. This property returns a unique identifier for all applications from the same vendor, where a vendor is determined by data provided from the App Store or the app's bundle identifier. As such, this property can be used to track a device only by a particular vendor. Removing the last application from the vendor causes the identifier to be removed, or if an application from the vendor is later reinstalled the identifier is reset. Nevertheless, you should ensure that this identifier is not unnecessarily exposed.

Processing the Address Book

The address book is perhaps one of the most sensitive data stores on an iOS device, and therefore understanding how it's used in an application and whether content is intentionally or inadvertently exposed is important. Before an application is able to access the address book it must first request permission from the user. If access is granted, an application has carte blanche access to the address book until the user manually revokes the permission from the Settings ➢ Privacy ➢ Contacts menu options. Some applications have abused this privilege, namely the “Find and Call” application (see http://www.wired.com/2012/07/first-ios-malware-found/) that uploaded users' address books and GPS coordinates to a remote server located in Russia.

When you review an iOS application, your methodology should include an investigation of whether an application can access the device's address book, what data it reads from it, and what it ultimately does with that data. Applications that access the address book will likely use the AddressBook framework (see https://developer.apple.com/library/ios/documentation/addressbook/reference/AddressBook_iPhoneOS_Framework/_index.html#//apple_ref/doc/uid/TP40007212). The use of ABAddressBookCopyArrayOfAllPeople and related methods should come under particular scrutiny. To help you identify whether an application uses this API call, consider using the Adios tool from Veracode (see https://www.veracode.com/security-tools/adios), which can automate this task for you.

Handling Geolocation Data

Apple provides a means of accessing the device's geolocation features using the Core Location framework. Device coordinates can be determined using GPS, cell tower triangulation, or Wi-Fi network proximity. When using geolocation data, developers should consider two main privacy concerns: how and where data is logged and the requested accuracy of coordinates.

Core Location is event driven, and an app looking to receive location information must register to receive event updates. Event updates can provide longitude and latitude coordinates for use in the app. As previously mentioned, an important part of reviewing an app is evaluating how this coordinate data is stored. If the app must store coordinate information client-side, the developer should protect this data using one of the data storage protection methods detailed in Chapter 5. However, to prevent someone from using the app to track a user's movements, location information should not be stored on the device. In addition to client-side logging, if the app passes coordinate information to a server, developers should ensure that any logging of this information is done so anonymously.

Another consideration for developers when requesting event updates is the accuracy of the information they require. For example, an app used for satellite navigation is likely to require very accurate location information, whereas an app that provides information about the closest restaurant does not need to be as accurate. Similar to location logging, the accuracy of the coordinates raises privacy concerns that developers should consider when writing iOS applications.

When using CLocationManager, an app can request accuracy using the CLLocationAccuracy class that offers the following constants:

  • kCLLocationAccuracyBestForNavigation
  • kCLLocationAccuracyBest
  • kCLLocationAccuracyNearestTenMeters
  • kCLLocationAccuracyHundredMeters
  • kCLLocationAccuracyKilometer
  • kCLLocationAccuracyThreeKilometers

When assessing an iOS application that uses location data, review how it uses this class and validate that the accuracy constants used are suitable for the application's use case.

Identifying Data Leaks

Many iOS applications unintentionally leak data to other applications or adversaries with access to the filesystem. In many cases, the data leaked can be of a sensitive nature, leading to the exposure of application secrets such as session cookies or even credentials. This type of data leakage typically occurs when a developer uses an API that has side effects the developer is not aware of and who therefore does not take preventative measures to secure the data.

This section documents some of the ways a developer using the iOS APIs may inadvertently leak sensitive application data.

Leaking Data in Application Logs

Logging can prove to be a valuable resource for debugging during development. However, in some cases it can leak sensitive or proprietary information, which is then cached on the device until the next reboot. Logging in an iOS application is typically performed using the NSLog method that causes a message to be sent to the Apple System Log (ASL). These console logs can be manually inspected using the Xcode device's application. Since iOS 7, ASL will only return data belonging to the application that requests it, preventing a malicious application from monitoring the log for secrets.

In the past, jailbreaking a device has caused NSLog output to be redirected to syslog. In this scenario the possibility exists for sensitive information to be stored on the filesystem in syslog. Therefore, developers should avoid using NSLog to log sensitive or proprietary information.

The simplest way for developers to avoid compiling NSLog into production releases is to redefine it with a dummy pre-processor macro such as #define NSLog(...).

Identifying Pasteboard Leakage

Many developers want to offer users the ability to copy and paste data to not only different areas of their application, but also to other applications on the device. If the pasteboard is used to copy sensitive data, depending on how it is implemented, data could be leaked from the pasteboard to other third-party applications. Three types of pasteboards are found in iOS applications:

  • The system pasteboard—This is the general pasteboard defined in the UIPasteboardNameGeneral constant of the UIPasteboard class. All applications can access data stored on this pasteboard.
  • The find pasteboard—This is typically used for search operations and contains the data from the most recent strings entered into the search bar. The find pasteboard is implemented using the UIPasteboardNameFind constant of the UIPasteboard class. All applications can access data stored on this pasteboard.
  • Custom pasteboards—Creating your own pasteboard is also possible using a unique identifier or a system-created identifier. Data placed on this pasteboard stays private to your application or family of applications.

When either of the first two pasteboards is used, the potential exists that data can be disclosed to any application that is passively monitoring the pasteboard. The following code snippet shows a simple example of how you could implement an application that passively monitors the pasteboard. This example launches a background task that reads the contents of the pasteboard every 5 seconds, and if the content has changed, sends it to the console log:

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    dispatch_async(dispatch_get_global_queue( \ 
    DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        UIApplication* uiapp = [UIApplication sharedApplication]; 
        UIBackgroundTaskIdentifier *bgTaskId; 
 
        bgTaskId = [uiapp beginBackgroundTaskWithExpirationHandler:^{}]; 
        NSString* contents = [[UIPasteboard generalPasteboard] string]; 
        while (true){ 
            NSString *newContents = [[UIPasteboard generalPasteboard] \ 
            string]; 
 
            if (![newContents isEqualToString:contents] && \ 
            newContents != nil){ 
                NSLog(@"Contents of pasteboard: %@",[[UIPasteboard \ 
                generalPasteboard] string]); 
                contents = [[UIPasteboard generalPasteboard] string]; 
            } 
            sleep(5); 
        } 
    }); 
}

Although such a simple example is unlikely to evade the App Store vetting process, it demonstrates how content stored on the pasteboard can be inadvertently disclosed to other applications.

To avoid disclosing data to all third-party applications on the device, you should use a custom pasteboard, which you can create as follows:

UIPasteboard *userPasteBoard =[UIPasteboard 
pasteboardWithName:@"MyAppDefinedPasteboard" create:YES]; 
userPasteBoard.persistent=YES;

At times an application might need to use the system pasteboard for certain fields. However, particularly sensitive fields such as passwords may not need the copy and paste functions so you can disable the copy and paste menu on individual UITextFields items using code similar to the following:

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender { 
    UIMenuController *menu = [UIMenuController \ 
    sharedMenuController]; 
    if (menu) { 
        menu.menuVisible = NO; 
    } 
    return NO; 
}

Handling Application State Transitions

When an application is open, the possibility exists for it to be sent into the background by a change in state, as a result of actions such as receiving an incoming call or the user pressing the home button. When an application is suspended in the background, iOS takes a snapshot of the app and stores it in the application's cache directory. When the application is reopened, the device uses the screenshot to create the illusion that the application loads instantly rather than taking time to reload the application.

If any sensitive information is open in the application when it enters the background, the snapshot is written to the filesystem in cleartext, albeit protected with the default data protection API class. Any system that can be paired with the device can access the snapshot. You can find the snapshot in the caches directory, as shown in Figure 4.1.

images

Figure 4.1 Accessing application snapshots with iExplorer

The snapshot is simply a PNG image that displays the current view of the device when the state change was initiated. Figure 4.2 shows how a registration page containing account information could be captured.

images

Figure 4.2 A snapshot can capture a registration page.

However, detecting when a state change is occurring and modifying the current view to mitigate against this type of data leakage is possible. You can use the UIApplication delegate method applicationDidEnterBackground to detect when an application is entering the background and from here the view can be masked. For example, if specific fields contain sensitive information, the application can hide these using the “hidden” attribute:

- (void)applicationDidEnterBackground:(UIApplication *)application { 
    viewController.accountNumber.hidden = YES; 
}

Conversely, when the application restarts, it can unhide these fields by doing the reverse in the applicationDidBecomeActive delegate:

- (void)applicationDidBecomeActive:(UIApplication *)application { 
    viewController.accountNumber.hidden = NO; 
}

Keyboard Caching

To improve the user experience, iOS attempts to customize the autocorrect feature by caching input that is typed into the device's keyboard. Almost every non-numeric word is cached on the filesystem in plaintext in the keyboard cache file located in /var/mobile/Library/Keyboard:

Ipod10:/var/mobile/Library/Keyboard root# strings en_GB-dynamic-text.dat 
DynamicDictionary-5 
burp 
call 
dialer 
admin 
http 
mdsec 
secret 
training

This has the obvious consequence that application data you wouldn't want to be cached—such as usernames, passwords, and answers to security questions—could be inadvertently stored in the keyboard cache.

However, you can prevent certain fields from being populated into the cache by either marking a field as a secure field using the secureTextEntry property or by explicitly disabling autocorrect by setting the autocorrectionType property to UITextAutocorrectionTypeNo. Here is an example of how to do this:

securityAnswer.autocorrectionType = UITextAutocorrectionTypeNo; 
securityAnswer.secureTextEntry = YES;

HTTP Response Caching

To display a remote website, an iOS application often uses a UIWebView to render the HTML content. A UIWebView object uses WebKit, the same rendering engine as MobileSafari, and just like MobileSafari a UIWebView can cache server responses to the local filesystem depending on how the URL loading is implemented.

You can find the cache data stored in the Cache.db database, located within the application's Library/Caches/ folder:

iPhone:# sqlite3 Cache.db 
SQLite version 3.7.13 
Enter ".help" for instructions 
sqlite> .tables 
cfurl_cache_blob_data       cfurl_cache_response 
cfurl_cache_receiver_data   cfurl_cache_schema_version 
sqlite>

Inside this database you find a number of tables that contain the response data and requested URL (cfurl_cache_response), response headers (cfurl_cache_blob_data), and the response blob (cfurl_cache_receiver_data); for example:

sqlite> select * from cfurl_cache_response limit 1; 
1|0|-479790032|0|http://sa.bbc.co.uk/bbc/bbc/s?name=news.page&ns_m2=yes&ns_setsi 
teck=546108443DC20193&ml_name=BBCBeacon_iOS&ml_version=3.5&app_name=news&ap 
p_version=2.1.4&app_type=mobile-app&prod_name=news& 
istats_visitor_id=c39770d71484042cfe5063f1c2bd2c93&ns__t=1415645252& 
orientation=portrait&app_edition=news-ios-uk|2014-11-1018:47:35| 
sqlite>

When sensitive content is returned in server responses, the possibility exists for it to be stored in the cache database. During any iOS application assessment, you should include an inspection of the cache database in your methodology to ensure that credentials or other sensitive content are not inadvertently cached.

Several strategies let you clear your application's cache or prevent it from caching at all, and the one that works best for you will depend on your implementation. To clear your cache and remove all stored cached URL responses you can use the following method:

[[NSURLCache sharedURLCache] removeAllCachedResponses];

While using NSURLConnection you can prevent caching on HTTPS responses using code similar to the following:

-(NSCachedURLResponse *)connection:(NSURLConnection *)connection 
willCacheResponse:(NSCachedURLResponse *)cachedResponse 
{ 
    NSCachedURLResponse *newCachedResponse=cachedResponse; 
    if ([[[[cachedResponse response] URL] scheme] isEqual:@"https"]) { 
        newCachedResponse=nil; 
    } 
    return newCachedResponse; 
}

Memory Corruption in iOS Applications

iOS applications are typically resistant to classic memory corruption issues such as buffer overflows if the developers rely on Objective-C or Swift to perform memory allocations because fixed sizes for buffers can't be specified. However, C can be intermingled with iOS apps, and seeing the use of external libraries or performance-dependent code, such as cryptography developed in C, is not uncommon. These approaches can give rise to the traditional memory corruption vulnerabilities. However, exploitation is no small task and subject to the device's built-in protection mechanisms, so other vulnerabilities are needed by someone trying to bypass these protection mechanisms. However, a small number of memory corruption issues have transcended into Objective-C and Swift, as detailed in the following sections.

Format String Vulnerabilities

Format string vulnerabilities form a class of memory corruption bugs that arise through the improper use of Objective-C or Swift methods that accept a format specifier. Vulnerable methods include but are not limited to the following:

  • NSLog
  • [NSString stringWithFormat]
  • [NSString stringByAppendingFormat]
  • [NSString initWithFormat]
  • [NSMutableString appendFormat]
  • [NSAlert alertWithMessageText]
  • [NSAlert informativeTextWithFormat]
  • [NSException format]
  • [NSMutableString appendFormat]
  • [NSPredicate predicateWithFormat]

Format string vulnerabilities arise when an attacker is able to provide the format specifier in part or as a whole to the relevant method. For example, consider the following:

NSString *myURL=@"http://10.0.2.1/test"; 
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL \ 
                           URLWithString:myURL]]; 
NSURLResponse *resp = nil; 
NSError *err = nil; 
NSData *response = [NSURLConnection sendSynchronousRequest: \ 
                   theRequest returningResponse:&resp error: &err]; 
NSString * theString = [[NSString alloc] initWithData:response \ 
                       encoding:NSASCIIStringEncoding]; 
NSLog(theString); 

In this example a request is made to a web server running on 10.0.2.1; the response is then stored in a NSData object, converted to an NSString, and logged using NSLog. In the documented usage of the NSLog function, NSLog is a wrapper for NSLogv and args is a variable number of arguments, as shown here:

void NSLogv ( 
   NSString *format, 
   va_list args 
);

However, in this instance the developer has supplied a single argument, allowing the attacker to specify the type of parameter that would be logged.

If you run the previous example in a debugger, you can see how the format string vulnerability can be triggered using a simple HTTP web server response:

bash-3.2# nc -lvp 80 
listening on [any] 80 . . . 
10.0.2.2: inverse host lookup failed: Unknown host 
connect to [10.0.2.1] from (UNKNOWN) [10.0.2.2] 52141 
GET /test HTTP/1.1 
Host: 10.0.2.1 
User-Agent: fmtstrtest (unknown version) CFNetwork/548.0.4 Darwin/11.0.0 
Accept: */* 
Accept-Language: en-us 
Accept-Encoding: gzip, deflate 
Connection: keep-alive 
 
HTTP/1.1 200 OK 
Content-Type: text/html; charset=utf-8 
Content-Length: 16 
 
aaaa%x%x%x%x%x%x

The HTTP response body is logged to NSLog and triggers the format string vulnerability, causing stack memory to be dumped to the console log, as shown here:

(gdb) r 
Starting program: /private/var/root/fmtstrtest 
2014-08-12 09:10:29.103 fmtstrtst[8008:303] 
aaaa124a600782fe5b84411f0b00 
Program exited normally. 
(gdb) 

To exploit traditional format string vulnerabilities an attacker can use the %n format specifier, which allows him to write to an arbitrary memory address read from the stack. However, this format specifier is not available in Objective-C or Swift. Instead, iOS format string vulnerabilities can be exploited using the %@ specifier that defines an object. Consequently, this may allow an arbitrary function pointer to be called.

Consider the following example that simply passes the value from argv[1] to NSLog:

int main(int argc, const char* argv[]) 
{ 
    NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init]; 
    NSString *n = [[NSString alloc] initWithCString:argv[1]]; 
    NSLog(n); 
    [pool drain]; 
    return 0; 
}

Popping enough data to reach the user-controlled part of stack memory, you can see how the %@ specifier causes a crash when dereferencing the pointer:

(gdb) r bbbbbbbbbbbbbbbb%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%x 
%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x 
%x%%x%x%x%x%x%x%x%x%x%x%@ 
Starting program: /private/var/root/fmtstrtest 
bbbbbbbbbbbbbbbb%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x 
%x%x%x%%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%x%x%x%x%x%x%x%%x%x%x%x%x%x%x%%x 
%x%x%x%x%x%x%x%x%x%@ 
 
Program received signal EXC_BAD_ACCESS, Could not access memory. 
Reason: KERN_INVALID_ADDRESS at address: 0x62626262 
0x320f8fb6 in ?? () 
(gdb)

Similarly, in Swift, insecure code that ultimately leads to a format string being evaluated such as,

var str = "AAAA%x%x%x%x%x%x%x%x" 
NSLog(str)

may lead to the following:

2014-11-10 20:53:58.245 fmtstrtest[22384:2258322] AAAA00000025852504

To prevent format string vulnerabilities, a secure implementation would include a format specifier, where NSLog(str) would become NSLog("%@", str). Swift also introduces the concept of interpolation, which allows you to create a string and easily populate it with other format types. Consider the following example that can be used to create a new string (see https://developer.apple.com/library/mac/documentation/swift/conceptual/swift_programming_language/StringsAndCharacters.html):

let multiplier = 3 
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"

Interpolation allows you to populate new types into a string by wrapping them in parentheses and prefixing them with a backslash. However, you should still use a format specifier if it is later passed into a method that requires one.

However, in most situations Objective-C and Swift will use the heap for storing objects and, therefore, in practice, exploitation is unlikely.

Object Use-After-Free

Object use-after-free vulnerabilities occur when a reference to an object still exists after the object has been freed. If this freed memory is reused and an attacker is able to influence the reused memory, in some circumstances it may be possible to cause arbitrary code execution. Exploitation of use-after-free vulnerabilities in Objective-C is documented in-depth within the Phrack article by nemo (http://www.phrack.org/issues.html?issue=66&id=4) and is recommended reading for those looking for a greater understanding of the topic. To demonstrate this type of exploitation at a high-level, consider the following example:

MAHH *mahh = [[MAHH alloc] init]; 
[mahh release]; 
[mahh echo: @"MAHH example!"];

In the previous example an instance of the MAHH class is first created and then freed using release. However, after the object has been released the echo method is called on the previously freed pointer. In this instance a crash is unlikely, because the memory will not have been corrupted through reallocation or deconstruction. However, consider an example whereby the heap has been sprayed with user-controlled data:

MAHH *mahh = [[MAHH alloc] init]; 
[mahh release]; 
for(int i=0; i<50000; i++) { 
    char *buf  = strdup(argv[1]); 
} 
[mdsec echo: @"MAHH example!"];

Running this example causes an access violation when the echo method is called due to the reuse of heap memory used by the previously freed object instance:

(gdb) r AAAA 
Starting program: /private/var/root/objuse AAAA 
 
Program received signal EXC_BAD_ACCESS, Could not access memory. 
Reason: KERN_INVALID_ADDRESS at address: 0x41414149 
0x320f8fbc in ?? () 
(gdb)

Since iOS 5, applications have had the option to use Automatic Reference Counting (ARC), which passes the responsibility of memory management from the developer to the compiler and is required for applications that use Swift. Consequently for applications using ARC, there is likely to be a significant reduction in the number of use-after-free issues, because the developer no longer bears the responsibility for releasing or retaining objects. For further details on ARC refer to Chapter 2.

Other Native Code Implementation Issues

Discovering native code programming vulnerabilities is a meaty topic and far beyond the scope of this book. However, for the moment it is sufficient to understand that when intermingled with C and C++, iOS applications can be affected by the traditional native code vulnerabilities such as buffer overflows, underflows, signedness issues, and the like. To learn more about these types of issues many resources are available; however, The Art of Software Security Assessment (ISBN-13: 978-0321444424; Dowd et al, Addison-Wesley Professional) is particularly comprehensive.

Summary

In this chapter you learned about the common categories of vulnerability to which iOS applications can be susceptible. Many of these issues arise by virtue of the iOS SDK APIs and may not be well known by developers, and as such commonly exist in real-world applications.

Many iOS applications are prone to data leakage, which can present a problem for security-conscious applications. Data leaks commonly occur as a result of an application's using features of the platform such as WebViews, which are often prone to caching response data and cookies, both of which can have a negative impact on the security of an application.

How applications handle personal and privacy-related data is also an important aspect of mobile security and should form a key portion of any application review. In particular, the device should not log or disclose any information pertaining to the user, the user's device, or location because doing so may turn the application into a tracking device.

Although occurring less frequently than in other types of applications, such as server-side services, memory corruption can occur in iOS applications. In practice, most memory corruption vulnerabilities in a third-party application will result in no more than a Denial of Service unless chained with other vulnerabilities.