CHAPTER 3
The Apple iPhone

image

Perhaps the most influential mobile device to enter the market in recent years is Apple’s iPhone. Arguably the first smartphone with mass-market appeal, the iPhone combines a sleek form factor, a multitouch screen, multimedia capabilities, highly functional Internet browsing, and impressive visual effects, all while maintaining an impressive battery life.

The iPhone has changed significantly since its initial introduction, growing to become the first platform with easy-to-use centralized application distribution, thus hugely increasing the market for mobile applications.

Because of its use of Objective-C, development on the iPhone carries the risk of security flaws traditionally associated with C software. However, some of these are masked by the high-level Cocoa Touch APIs, and therefore require special attention. And because Apple has relatively little documentation available on security best practices, developers are often unaware of these risks.

History

The release of the iPhone in June 2007 was not entirely unexpected, but what was surprising was the device’s sheer level of sophistication. The interface design was unprecedented, and combined with the device’s skinny-pants-compatible form factor, it seemed too good to be true. Many assumed it would get abysmal battery life, but Apple delivered even on this. The functionality at launch was basic, but also polished and impressive.

In January 2008, Apple released the next main update to the iPhone OS, version 1.1.3. This introduced services such as geolocation, increased SMS capabilities, and several UI and bug-fix improvements.

Some of the big features introduced with iPhone OS 2.0 (released in July 2008) included support for enterprise use (including Microsoft Exchange compatibility, remote wipe, and viewing of popular office document formats) and, most importantly, the introduction of the App Store, the first centralized mechanism to distribute software on a mobile platform. Somewhat audaciously, Apple has claimed its right to exclusively control what software can be run on the platform, a first from a modern operating system vendor.

The latest version of the iPhone OS, version 3.0, brings a slew of new features. It provides copy-and-paste functionality to the iPhone (welcome to the 1970s!) using the NSPasteBoard API, but also adds several other long-awaited features, such as MMS, pervasive landscape typing mode, Spotlight search, and notification services for third-party applications, to work around the limitation that only one application can run at a time. The Core Data API from Cocoa can also now be used to design data models.

The iPhone and OS X

Both the iPhone and Mac OS X share the usage of Objective-C and a large part of the Cocoa API. However, a number of components worth noting are missing or have been changed on the iPhone’s Cocoa implementation (Cocoa Touch). Although the Core Data API, introduced in Tiger, is now in iPhone OS 3.0, garbage collection, as introduced in OS X 10.5/Objective-C 2.0, is still absent. This means that developers must use the traditional retain/release method of tracking object references.

Unlike most of the operating systems discussed in this book, the iPhone OS is potentially susceptible to classic C vulnerabilities, such as buffer overflows, integer overflows, and format string attacks. We’ll discuss the mitigation of these attacks in the section “Security Testing.”

Breaking Out, Breaking In

Even before Apple released any software development kit (SDK) for the iPhone, developers were already writing applications for deployment on the device. “Jailbreaking” the iPhone allowed for the running of unsigned code and the free modification of the underlying file system. Combined with carrier unlocking, users could also be free of AT&T and use their choice of another provider (and there are several good reasons to—see http://www.eff.org/cases/att). In the U.S., the only available alternative is T-Mobile on the 2G iPhone. In Europe, the AT&T partnership is not in effect, and 3G service is, in fact, provided through T-Mobile by default.

Jailbreaking remains the only option for implementing some functionality. Apple doesn’t allow official applications to run in the background, and it doesn’t allow you to implement functionality that the company may implement in the future (for example, recording video) or that violates agreements Apple has with its vendors (for example, downloading YouTube videos for offline use). Therefore, many useful applications that cannot be distributed through the App Store can be run on the device via other channels.

Recently, the unauthorized application installer Cydia (http://cydia.saurik.com) has begun distributing commercial applications, giving an outlet for developers to sell unapproved applications. It remains to be seen how successful this will be, but a reasonably large portion of the user base does use “jailbroken” phones.

At Chaos Communication Congress 2008, the “iPhone Dev Team” (not the true Apple iPhone development team, of course) demonstrated an unlock of the baseband of the iPhone 3G, again showing that the arms race between Apple and phone unlockers will continue for the foreseeable future. As of this writing, the prerelease iPhone OS 3.0 can reportedly still be jailbroken.

iPhone SDK

After the initial outcry over not providing an SDK for third-party developers to write for the iPhone platform, Apple capitulated and announced the so-called “AJAX SDK,” which was near-universally bemoaned by developers because it provided fairly little functionality.

After the public response to a solely web-based application platform, Apple introduced the real iPhone SDK in March 2008. Unfortunately, Apple somewhat botched the second SDK release as well, by releasing it only to developers who paid a per-year licensing fee and accepted a draconian nondisclosure agreement (NDA). Because this agreement prevented discussion of the SDK, even with other developers, the iPhone development community largely didn’t take off until October 2008, when the NDA was finally dropped (although license agreements remain in effect).

iPhone SDK 3.0 is the current standard, and the one we cover in this chapter.

Future

As with any Apple product, rumors abound regarding new product and functionality releases. More generally, it has been speculated that the iPhone OS and Mac OS X will gradually merge in the future, as mobile hardware becomes more capable. Under pressure from new contenders such as Android, Apple has implemented notification services for third-party apps as well as opened up formerly proprietary functionality (such as the iPod library access) to third-party developers.

Development

Development for the iPhone is performed with Xcode and the iPhone SDK. Code can be run either within the emulator or on a development device. For some applications (for example, those using the Keychain), a physical device is required. Debugging is done within Xcode via gdb, although for jailbroken devices, a third-party gdb can be installed on the device itself for debugging any phone application.

Decompilation and Disassembly

Objective-C applications decompile fairly cleanly, if you have the right tools. Many Apple developers may be familiar with otool, which comes with the OS X developer tools. otool is a straightforward executable disassembler that can parse Mach-O type executables. otool has also been ported to ARM and is available via several sources. otool is very flexible; see otool(1) for details. Here’s a common usage:

NOTE

In Cydia, the package that includes otool is Darwin CC Tools. We, of course, take no responsibility for anything bad that happens from running sketchy Cydia apps!

otool -toV /Applications/iCal.app/Contents/MacOS/iCal

/Applications/iCal.app/Contents/MacOS/iCal:
Objective-C segment
Module 0x22b52c
    version 7
       size 16
       name
     symtab 0x0022c940
        sel_ref_cnt 0
        refs 0x00000000 (not in an __OBJC section)
        cls_def_cnt 1
        cat_def_cnt 0
        Class Definitions
        defs[0] 0x00204360
                      is a 0x0020a560
              super_class 0x001a5f44 CALCanvasItem
                     name 0x001c6574 CALCanvasAttributedText
                  version 0x00000000
                     info 0x00000001 CLS_CLASS
            instance_size 0x0000015c
                    ivars 0x00224300
                       ivar_count 13
                        ivar_name 0x001a54e2 _text
                        ivar_type 0x001a53d0
@“NSMutableAttributedString”
                      ivar_offset 0x0000012c
                        ivar_name 0x001a54e8
_displayedTextNeedsUpdate
                        ivar_type 0x001a5940 c
                      ivar_offset 0x00000130
                        ivar_name 0x001a5502 _generalAttributes
                        ivar_type 0x001a665c @“NSMutableDictionary”
                      ivar_offset 0x00000134
                        ivar_name 0x001a66dc _fontName
                        ivar_type 0x001a6020 @“NSString”
                      ivar_offset 0x00000138
                        ivar_name 0x001a6034 _fontSize
<and much, much more>

Try running this on several OS X or iPhone binaries using grep to search for interesting strings.

For current versions of the iPhone OS (verified on 3.0), you can use the class-dump or class-dump-x tools (http://iphone.freecoder.org/classdump_en.html; also available in Cydia and in MacPorts for OS X) to get very readable information on class declarations and structs from Objective-C object code. You have the option of either installing the iPhone binary on a jailbroken device or running the binary under OS X. Because of the architectural difference between the phone and Intel Macs, you’ll need to run the tool against packages compiled for the iPhone simulator.

From the OS X Terminal (Applications | Utilities | Terminal), you can do the following:

NOTE

For more information on using the Terminal under OS X, see http://onlamp.com/pub/ct/51.

class-dump-x /Developer/Platforms/iPhoneSimulator
.platform/Developer/ SDKs/iPhoneSimulator3.0.sdk/Applications
/MobileSafari.app
  < snip >
  protocol CALCanvasTextProtocol

- (id)attributes;
- (id)foregroundColor;
- (float)fontSize;
@end
@protocol CALDetachmentDelegate
- (int) decideDetachmentFor:(id)fp8 withOccurrence:(id)fp12 ;
@end
@protocol CALSubscribeOperationUIHandler
- (BOOL)acceptHandlingOfSubscribeCreationOperation:(id)fp8;
- (BOOL)handleSubscribeCreationErrorForOperation:(id)fp8;
- (id)displayStringForSubscribeCreationNotification:(id)fp8;
- (id)calendarIDOfSourceForOperation:(id)fp8;
- (id)handleSubscribeCreationPostDownloadForOperation:(id)fp8
autoRefreshChoices :(id)fp12;
@end
@protocol CalControllerProtocolDelegate
- (void)selectNode:(id)fp8 checked:(int)fp12 ;
- (void)selectAndShowEntity:(id)fp8;
- (void)removeAllSelectedObjects;
@end

As you can see, this code outputs declarations of the classes and protocols used by the Mobile Safari application. Of course, this is only useful if you’ve come across an x86-compiled iPhone app that you need to disassemble—which is not terribly likely, unless you’re trying to reverse-engineer the Apple-provided apps. For most cases, you’ll want to use a jailbroken phone and then ssh into the device to use the iPhone version of class-dump-x and/or otool.

Another tool that expands on the output of class-dump by resolving additional symbols is otx (http://otx.osxninja.com). Although not runnable on the iPhone itself, otx is another tool that can give you some insight into what is visible when others are examining your applications. Listing 3-1 shows some otx output.

Listing 3-1 otx Output

image

image

Preventing Reverse-Engineering

At this point, you may be asking yourself, “What can I do to prevent people from reverse-engineering my programs?” The answer is quite simply: You can’t do much. If someone is motivated to crack or reverse-engineer your application, they can use far more powerful commercial tools than these to make doing so even easier. Plus, the development effort required to prevent reverse-engineering costs money, especially if you have to revise your protection or obfuscation mechanisms.

If you absolutely can’t be dissuaded from implementing some form of “copy protection” or activation scheme, you can try to hide from some of the aforementioned mechanisms such as class-dump by putting your logic into plain C or C++ and ensuring that you strip your binaries. But don’t burn a lot of time on this—remember that all these schemes can be easily defeated by a knowledgeable attacker.

Security Testing

The threat of classic C exploits is reduced, but not eliminated, by using high-level Objective-C APIs. This section discusses some best practices, such as using NSString rather than legacy string operations like strcat and strcpy to protect against buffer overflows. However, there are a few more subtle ways that things can go wrong.

Buffer Overflows

The buffer overflow is one of the oldest and most well-known exploitable bugs in C. Although the iPhone has some built-in preventative measures to prevent buffer overflow exploitation, exploits resulting in code execution are still possible (see http://www.blackhat.com/presentations/bh-europe-09/Miller_Iozzo/BlackHat-Europe-2009-Miller-Iozzo-OSX-IPhone-Payloads-whitepaper.pdf). At their most basic level, buffer overflows occur when data is written into a fixed-size memory space, overflowing into the memory around the destination buffer. This gives an attacker control over the contents of process memory, potentially allowing for the insertion of hostile code. Traditionally, C functions such as strcat() and strcpy() are the APIs most often abused in this fashion. Sadly, these functions are still sometimes used in iPhone applications today.

The simplest way for an Objective-C programmer to avoid buffer overflows is to avoid manual memory management entirely, and use Cocoa objects such as NSString for string manipulation. If C-style string manipulation is necessary, the strl family of functions should be used (see http://developer.apple.com/documentation/security/conceptual/SecureCodingGuide/Articles/BufferOverflows.html).

Integer Overflows

An “integer overflow” occurs when a computed value is larger than the storage space it’s assigned to. This often happens in expressions used to compute the allocation size for an array of objects because the expression is of the form object_size × object_count. Listing 3-2 shows an example of how to overflow an integer.

Listing 3-2 How to Overflow an Integer

   int * x = malloc(sizeof (*x) * n);
   for (i = 0; i < n; i++)
      x[i] = 0;


If n is larger than 1 billion (when sizeof(int) is 4), the computed value of

sizeof (*x) * n

will be larger than 4 billion and will result in a smaller value than intended. This means the allocation size will be unexpectedly small. When the buffer is later accessed, some reads and writes will be performed past the end of the allocated length, even though they are within the expected limits of the array.

It is possible to detect these integer overflows either as they occur or before they are allowed to occur by examining the result of the multiplication or by examining the arguments. Listing 3-3 shows an example of how to detect an integer overflow.

Listing 3-3 Detecting an Integer Overflow

   void *array_alloc(size_t count, size_t size) {
     if (0 == count || MAX_UINT / count > size)
         return (0);

     return malloc(count * size);
}


It’s worth noting at this point that NSInteger will behave exactly the same way: It’s not even actually an object, but simply an Objective-C way to say “int.”

Format String Attacks

Format string vulnerabilities are caused when the programmer fails to specify how user-supplied input should be formatted, thus allowing an attacker to specify their own format string. Apple’s NSString class does not have support for the “%n” format string, which allows for writing to the stack of the running program. However, there is still the threat of allowing an attacker to read from process memory or crash the program.

NOTE

Valid format strings for the iPhone OS can be found at http://developer.apple.com/iphone/library/documentation/CoreFoundation/Conceptual/CFStrings/formatSpecifiers.html.

Listing 3-4 shows an example of passing user-supplied input to NSLog without using a proper format string.

Listing 3-4 No Format Specifier Used

int main(int argc, char *argv[]) {

    NSString * test = @”%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x”;
    NSLog(test);
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
     [pool release];
    return retVal;
}


Running this results in the following:

[Session started at 2009-03-14 22:09:06 -0700.]
2009-03-14 22:09:08.874 DemoApp[2094:20b]
000070408fe0154b10000bffff00cbfffef842a4e1bfffef8cbfffef94bffff00c0

Whoops! Our user-supplied string resulted in memory contents being printed out in hexadecimal. Because we’re just logging this to the console, it isn’t too big a deal. However, in an application where this output would be exposed to a third party, we’d be in trouble. If we change our NSLog to format the user-supplied input as an Objective-C object (using the “%” format specifier), we can avoid this situation, as shown in Listing 3-5.

Listing 3-5 Proper Use of Format Strings

int main(int argc, char *argv[]) {

    NSString * test = @”%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x”;
    NSLog(@”%@”, test);
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
     [pool release];
    return retVal;
}


NSLog makes for a good demo but isn’t going to be used that often in a real iPhone app (given that there’s no console to log to). Common NSString methods to watch out for are stringByAppendingFormat, initWithFormat, stringWithFormat, and so on.

One thing to remember is that even when you’re using a method that emits NSString objects, you still must specify a format string. As an example, say we have a utility class that just takes an NSString and appends some user-supplied data:

+ (NSString*) formatStuff:(NSString*)myString
{
    myString = [myString stringByAppendingString:userSuppliedString];
    return myString
}

When calling this method, we use code like the following:

NSString myStuff = @“Here is my stuff.”;
myStuff = [myStuff stringByAppendingFormat:[UtilityClass
formatStuff:unformattedStuff.text]];

Even though we’re both passing in an NSString and receiving one in return, stringByAppendingFormat will still parse any format string characters contained within that NSString. The correct way to call this code would be as follows:

NSString myStuff = @“Here is my stuff.”;
myStuff = [myStuff stringByAppendingFormat:@“%@”, [UtilityClass
formatStuff:unformattedStuff.text]];

When regular C primitives are used, format strings become an even more critical issue because the use of the “%n” format can allow for code execution. If you can, stick with NSString. Either way, remember that you, the programmer, must explicitly define a format string.

Double-Frees

C and C++ applications can suffer from double-free bugs, where a segment of memory is already freed from use and an attempt is made to deallocate it again. Typically, this occurs by an extra use of the free() function, after a previously freed memory segment has been overwritten with attacker-supplied data. This results in attacker control of process execution. In its most benign form, this can simply result in a crash. Here’s an example:

if (i >= 0) {
  …
  free(mystuff);
}

free(mystuff);

In Objective-C, we can run into a similar situation where an object allocated with an alloc is freed via the release method when it already has a retain count of 0. An example follows:

id myRedCar = [[[NSString alloc] init] autorelease];

[myRedCar release];

Here, because myRedCar is autoreleased, it will be released after its first reference. Hence, the explicit release has nothing to release. This is a fairly common problem, especially when methods are used that return autoreleased objects. Just follow the usual development advice: If you create an object with an alloc, release it. And, of course, only release once. As an extra precaution, you may wish to set your object to nil after releasing it so that you can explicitly no longer send messages to it.

NOTE

See http://weblog.bignerdranch.com/?p=2 for more information on debugging retain counts. The majority of information here is applicable to both OS X and the iPhone.

Static Analysis

Most commercial static analysis tools haven’t matured to detect Objective-C-specific flaws, but simple free tools such as Flawfinder (http://dwheeler.com/flawfinder/) can be used to find C API abuses, such as the use of strcpy and statically sized buffers. Apple has documentation on implementing “static analysis,” but it seems to have misunderstood this to mean simply turning on compiler warnings (see http://developer.apple.com/TOOLS/xcode/staticanalysis.html).

A more promising application is the Clang Static Analyzer tool, available at http://clang.llvm.org/StaticAnalysis.html. Like any static analysis tool, the clang analyzer has its share of false positives, but it can be quite useful for pointing out uninitialized values, memory leaks, and other flaws. To use this tool on iPhone projects, you’ll need to do the following:

1. Open your project in Xcode. Go to Project | Edit Project Settings.

2. Go to Build. Change “Configuration” to “Debug.”

3. Change the Base SDK to “Simulator” of the appropriate OS version. “Valid Architectures” should change to “i386.”

4. Go to Configurations and change the default for command-line builds to be “Debug.”

5. In a terminal, cd to the project’s directory and run scan-build –view xcodebuild.

6. When the build completes, a browser window will be opened to a local web server to view results.

Consult the clang documentation for more details on interpreting the results. Of course, you should not assume that the use of a static analysis tool will find all or even most of the security or reliability flaws in an application; therefore, you should consider developing fuzzers for your program’s various inputs.

The role of a fuzzer is to expose faults through violating program assumptions. For instance, given an application that parses an HTTP response and populates a buffer with its contents, over-long data or format strings can cause the program to fail in a potentially exploitable fashion. Similarly, integers retrieved via external sources could fail to account for negative numbers, thus leading to unexpected effects. You can craft fuzzers in the form of fake servers, fake clients, or programs that generate many test cases to be parsed by an application. For more information on fuzzers, see http://en.wikipedia.org/wiki/Fuzz_testing.

Application Format

In contrast to OS X, the iPhone platform does not use an intermediate compression format for applications such as DMG or StuffIt—and of course, there is no concept of “Universal” binaries. Rather, they are distributed directly as an application bundle. In this section we take a closer look at the build and packaging characteristics of iPhone applications, as well as code signing and distribution.

Build and Packaging

Applications are compiled via Xcode similarly to OS X applications, using the GNU GCC compiler, cross-compiled for the ARM processor of the iPhone device, as well as for the local machine, to run in the emulator. Each application bundle includes a unique application ID, a plist of entitlements and preferences, a code signature, any required media assets or nib files, and the executable itself.

As with an OS X application, bundles must include an Info.plist, which specifies the majority of the metadata about the application. Every Xcode-created project will include an Info.plist under the Resources hierarchy. One or more preference plists (Root.plist) can be included for application-specific preferences.

Distribution: The Apple Store

Apple’s Application Store was the first user experience that made acquiring mobile applications a simple task. Apple exercises total control over the content of the Application Store; all iPhone applications must be approved prior to distribution, and can be revoked at Apple’s discretion. The rules for forbidden applications are something of a moving target, and therefore are difficult to enumerate. However, with the advent of iPhone OS 3.0, Apple seems to be making moves to loosen these restrictions.

Although there are many disadvantages to this approach, it does mean that the App Store serves as a security boundary. Programmatic security mechanisms for applications running on the iPhone OS are fairly lax, but Apple can rein in developers behaving in a deceptive or malicious fashion by refusing to publish their applications or revoking them from the store.

In the event actively malicious software does make it through the App Store, a second approach, albeit one that has yet to be used by Apple, is a “kill switch” allowing the blacklisting of applications after install. Although there were some initial worries that Apple would be using this to actively disable software it didn’t like, this has not been the case to date.

Thus far, using Apple itself as the gatekeeper and security boundary for iPhone applications has had good results—except for developers, some of whom have had wait times of up to six months just to get an application accepted. With the sheer number of new iPhone applications appearing on a daily basis, it’s not unlikely that more OS-based security features will be used more actively in the future to smooth out the application-vetting process.

Code Signing

iPhone applications must be signed by a valid code-signing certificate. Some applications, notably ones that use the Keychain or cryptography primitives, are designed only to be run on an actual device, rather than an emulator. To obtain a code-signing certificate, use the Keychain Access tool to create a Certificate Signing Request (CSR), as described in Apple’s Code Signing Guide (see http://developer.apple.com/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html). Once the certificate has been issued (a fairly quick process), you can import the certificate into your Keychain.

If you don’t have a membership with the iPhone Developer Program, it is still possible to use self-signed certificates to sign applications. However, this involves disabling security checks in the device, which is ill-advised for devices that aren’t used solely for development. For more information on the mechanisms behind Apple signature verification and how to bypass them, see Jay Freeman’s page at www.saurik.com/id/8.

Executing Unsigned Code

As mentioned before, third-party iPhone applications existed before the App Store. On “jailbroken” phones, using Cydia and Installer are the two most popular ways to install unauthorized third-party software. Even without submitting your packages to a public repository, you can still execute unsigned code on your device.

Once jailbroken, the iPhone can run an SSH daemon that can be used to copy unsigned applications onto the device. These applications can even run outside of the default Apple sandboxing policies. To sideload your sneaky, illicit iPhone application onto a device, you can perform the following steps:

1. Using Cydia, install the BSD Subsystem and OpenSSH packages.

2. Find the IP address of your iPhone by examining the Network Settings panel.

3. Using your OS X machine, open the Terminal application.

4. Type ssh [email protected], where 10.20.30.40 is the IP address of your phone. When asked for a password, enter alpine.

5. The first order of business should be to change the device’s root password. Enter the command passwd to do this.

6. You can now copy your application to the device. To do this, archive the application on your OS X machine using tar -cvzf myapp.tar.gz MyApp, where MyApp is the application bundle.

7. Copy the bundle to the device using scp myapp.tar.gz [email protected].

8. Once the archive is copied over, ssh back into the iPhone and cd to the Applications directory.

9. Execute tar -xvzf myapp.tar.gz. The application will be extracted.

10. Restart your springboard (with BossPrefs, for example) or reboot your device. Your application should appear on the springboard.

Permissions and User Controls

Several approaches to mobile application sandboxing have been attempted by various vendors. Apple has chosen to use Mandatory Access Controls (MAC) as its mechanism for restricting the capabilities of applications, which has the advantages of being extremely flexible and of spelling “MAC”. Additional permissions are exposed directly to the user in the form of prompts.

Sandboxing

The iPhone OS and OS X permission system is based on the TrustedBSD framework, developed in large part by Robert Watson from the FreeBSD project. Apple has variously referred to its implementation as sandbox and seatbelt. We’ll be referring to it as seatbelt here, which is the name of the actual kernel sandboxing mechanism, and use sandbox as a verb. This system allows for writing policy files that describe what permissions an application should have. Under OS X, users can create new policies to sandbox applications on their system, to prevent compromised applications from affecting the rest of the system. On the iPhone, seatbelt is used to partition applications from each other and to prevent a malicious application from modifying the underlying system or reading data meant for other applications. The policy used for this is not public, but we have a pretty good idea how it actually works.

Each application is installed into its own directory, identified as a GUID. Applications are allowed limited read access to some system areas, but are not allowed to read or write directories belonging to other applications in /private/var/mobile/Applications. Access to the Address Book and Photos is explicitly allowed. We can’t publish it here, but as of iPhone OS 2.1, you can find the default seatbelt template in /usr/share/sandbox/SandboxTemplate.sb. Examination of this policy gives a fairly clear view of the purpose and particulars of iPhone sandboxing.

Exploit Mitigation

In the current 3.x branch of the iPhone OS, both the heap and stack are nonexecutable by default, making it more secure in this area than regular OS X (which does have an executable heap). It does not, however, include ASLR (Address Space Layout Randomization), while OS X does, albeit using a rather incomplete implementation. setreuid and setreguid have been removed from the kernel to prevent processes from even requesting to change user and group IDs.

Code signing can also reduce the risk of execution of unauthorized third-party code, because any file an exploit is able to write out to disk cannot be executed (on a standard, non-jailbroken iPhone).

The ARM architecture itself is somewhat more resilient against classic memory corruption attacks than the i386 architecture used by modern Macs.

NOTE

A whitepaper on this subject can be found at http://www.blackhat.com/presentations/bh-europe-09/Miller_Iozzo/BlackHat-Europe-2009-Miller-Iozzo-OSX-IPhone-Payloads-whitepaper.pdf.

image


Figure 3-1 The iPhone geolocation permissions dialog

Permissions

Permission granting for specific functionality is granted via pop-ups to the user at the time of API use (rather than upon installation, as with systems such as Android). The most common of these is a request to use geolocation features (see Figure 3-1).

Another common permission request is to grant the ability to read data from the camera. Notably absent is a permissions dialog for recording audio.

Local Data Storage: Files, Permissions, and Encryption

As mobile applications store more and more local data, device theft is becoming an increasing concern, especially in the enterprise. To ensure that data cannot be obtained either by theft of the device or by a network attacker, we’ll look at best practices for storing local data securely. Developers must not rely on the “device encryption” functionality of the iPhone 3GS; this mechanism is not robust against a dedicated attacker (see www.wired.com/gadgetlab/2009/07/iphone-encryption), and special effort must still be made by the developer to keep data safe.

SQLite Storage

A popular way to persist iPhone application data is to store it in an SQLite database. When using any type of SQL database, you must consider the potential for injection attacks. When writing SQL statements that use any kind of user-supplied input, you should use “parameterized” queries to ensure that third-party SQL is not accidentally executed by your application. Failure to sanitize these inputs can result in data loss and/or exposure.

Listing 3-6 shows the wrong way to write SQLite statements.

Listing 3-6 Dynamic SQL in SQLite

NSString *uid = [myHTTPConnection getUID];
NSString *statement = [NSString StringWithFormat:@“SELECT username
FROM
    users where uid = ’%@’”, uid];
const char *sql = [statement UTF8String];
sqlite3_prepare_v2(db, sql, -1, &selectUid, NULL);
sqlite3_bind_int(selectUid, 1, uid);
int status = sqlite3_step(selectUid);
sqlite3_reset(selectUid);


Here, the parameter uid is being fetched from an object that presumably originates from input external to the program itself (that is, user input or a query of an external connection). Because the SQL string is concatenated with this external input, if the string contains any SQL code itself, this will be concatenated as well, thus causing unexpected results.

A proper, parameterized SQL query with SQLite is shown in Listing 3-7.

Listing 3-7 Parameterized SQL in SQLite

const char *sql = “SELECT username FROM users where uid = ?”;
sqlite3_prepare_v2(db, sql, -1, &selectUid, NULL);
sqlite3_bind_int(selectUid, 1, uid);
int status = sqlite3_step(selectUid);
sqlite3_reset(selectUid);

Not only is this safer by ensuring that uid is numeric, but you’ll generally get a performance boost using this technique over dynamic SQL query construction. Listing 3-8 shows similar binding functions for other data types.

Listing 3-8 SQLite Binding

sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n,
void(*)(void*));
sqlite3_bind_double(sqlite3_stmt*, int, double);
sqlite3_bind_int(sqlite3_stmt*, int, int);
sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
sqlite3_bind_null(sqlite3_stmt*, int);
sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n,
void(*)(void*));
sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int,
void(*)(void*));
sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);


Of course, now that Core Data is supported in iPhone OS 3.0, this will likely become the preferred method of data storage. Core Data internally saves information to a SQLite database by default. Using Core Data is generally a good approach, but it does remove some flexibility—an example would be using custom builds of SQLite such as SQLCipher, which can provide transparent AES encryption. Secure storage of smaller amounts of data can be done with the Keychain.

iPhone Keychain Storage

The iPhone includes the Keychain mechanism from OS X to store credentials and other data, with some differences in the API and implementation. Because the iPhone has no login password, only a four-digit PIN, there is no login password to use for the master encryption key on the iPhone. Instead, a device-specific key is generated and stored in a location inaccessible to applications and excluded from backups.

The API itself is different from the regular Cocoa API, but somewhat simpler. Rather than secKeychainAddInternetPassword, secKeychainAddGenericPassord, and so on, a more generic interface is provided: SecItemAdd, SecItemUpdate, and SecItemCopyMatching.

Another difference with the iPhone Keychain is that you can search for and manipulate Keychain items by specifying attributes describing the stored data. The data itself is stored in a dictionary of key/value pairs. One thing common to the Keychain on both platforms, however, is that it’s somewhat painful to use, considering most people just need to save and retrieve passwords and keys.

NOTE

A complete list of available attributes is available at http://developer.apple.com/iphone/library/documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/.

The iPhone Keychain APIs only work on a physical device. For testing in a simulator, one has to use the regular OS X Keychain APIs. One reasonable simplification to this process is by Buzz Andersen, at http://github.com/ldandersen/scifihifi-iphone/tree/master/security. This code shows how to use a simple API for setting and retrieving Keychain data, which uses OS X native APIs when built for a simulator but iPhone APIs for a device build.

Shared Keychain Storage

With iPhone OS 3.0, the concept of shared Keychain storage was introduced, allowing for separate applications to share data by defining additional “Entitlements” (see Chapter 2 of the iPhone Development Guide). To share access to a Keychain between applications, the developer must include the constant kSecAttrAccessGroup in the attributes dictionary passed to SecItemAdd as well as create an Entitlement.

The Entitlement should take the form of a key called “keychain-access-groups” with an array of identifiers that define application groups. For instance, an identifier of com.conglomco.myappsuite could be added to all apps that Conglomco distributes, allowing sign-on to Conglomco services with the same credentials. Each application will also contain its own private section of the Keychain as well.

What keeps other applications from accessing your shared Keychain items? As near as I can tell, nothing. This is another area where the App Store will probably be relied upon to weed out malicious apps. However, until more details are published about the proper use of shared Keychains, it is probably prudent not to store sensitive data in them—which is to say, don’t use them at all.

Adding Certificates to the Certificate Store

If you need to work with the iPhone using Secure Sockets Layer (SSL) in a test environment—and you should configure your test environment to use SSL!—here are three different options you have:

image    Install your internal CA certificate on a machine that syncs to an actual iPhone via iTunes.

image    Retrieve the certificate from a web server using Safari.

image    Mail the certificate to the phone.

Because in all likelihood you’ll be working primarily with the iPhone emulator, the second option is your best bet. When accessing a certificate via e-mail or Safari, you will be prompted with the “Install Profile” dialog (see Figure 3-2). Clicking “Install” will store the certificate in the phone’s internal certificate store. As of iPhone OS 3.0, you can remove these or view certificate details (see Figure 3-3) by going to Settings | General | Profiles.

Acquiring Entropy

Strong entropy on the iPhone is acquired through the SecRandomCopyBytes API, which reads random data from the device’s Yarrow Pseudo-Random Number Generator, a.k.a. /dev/random (see http://www.schneier.com/paper-yarrow.ps.gz).

image


Figure 3-2 Installing a third-party CA certificate

image


Figure 3-3 Certificate details

This function takes three parameters: the random number generator to use (which will always be kSecRandomDefault at this point), the number of random bytes to return, and the array in which to store them. A sample usage can be found in the CryptoExercise sample code provided on ADC (see Listing 3-9).

Listing 3-9 Generating a Symmetric Key

symmetricKey = malloc (kChosenCipherKeySize * sizeof(uint8_t));
memset((void *)symmetricKey, 0x0, kChosenCipherKeySize);
sanityCheck = SecRandomCopyBytes(kSecRandomDefault,
kChosenCipherKeySize,
symmetricKey);


Networking

There are several available mechanisms for obtaining resources over network connections on the iPhone, depending on whether your needs are for loading content over HTTP/FTP, doing lower level socket manipulation, or networking with other devices over Bluetooth. We’ll look first at the most common mechanism, the URL loading API.

The URL Loading API

The URL Loading API supports HTTP, HTTPS, FTP, and file resource types; these can be extended by subclassing the NSURLProtocol class. The normal way to interface to this API is via NSURLConnection or NSURLDownload, using an NSURL object as the input (see Listing 3-10).

Listing 3-10 Using NSURLConnection (Sample Code from Apple’s “URL Loading System Overview”)

  NSURL *myURL = [NSURL URLWithString:@“https://cybervillains.com/”];

NSMutableURLRequest *myRequest = [NSMutableURLRequestrequestWithURL:
                            myURLcachePolicy:NSURLRequestReload
                            IgnoringCacheDatatimeoutInterval:60.0];

[[NSURLConnection alloc] initWithRequest:myRequest
                           delegate:self];


The request object simply gathers all the properties of the request you’re about to make, with NSURLConnection performing the actual network connection. Requests have a number of methods controlling their behavior—one method that should never be used is setAllowsAnyHTTPSCertificate.

I hesitate to even mention it, should it make some foolhardy developer aware of it. However, for the benefit of penetration testers and QA engineers who have to look specifically for terrible ideas, I’ll specifically call out: Don’t use this method. The correct solution is to update the certificate store; see “Adding Certificates to the Certificate Store,” earlier in this chapter.

By default, HTTP and HTTPS request results are cached on the device. For increased privacy, you may consider changing this behavior using a delegate of NSURLConnection implementing connection:willCacheResponse (see Listing 3-11).

Listing 3-11 Using NSURLConnection

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


One surprise about the NSURL family is that all cookies stored are accessible by any application that uses the URL loading system (http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/URLLoadingSystem/Concepts/URLOverview.html#//apple_ref/doc/uid/20001834-157091). This underscores the need to set reasonable expiration dates on cookies, as well as to refrain from storing sensitive data in cookies.

NSStreams

Cocoa Socket Streams are most useful when the need arises to use network sockets for protocols other than those handled by the URL loading system, or in places where you need more control over how connections behave. To do this, you have to create an NSStream object, instructing it to receive input, send output, or both. For most networking purposes, both will be required (see Listing 3-12).

Listing 3-12 Creating a Socket Stream

// First we define the host to be contacted
NSHost *myhost = [NSHost hostWithName:[@“www.conglomco.com”]];

// Then we create
[NSStream getStreamsToHost:myhost
                      port:80
               inputStream:&MyInputStream
              outputStream:&MyOutputStream];

[MyInputStream setProperty:NSStreamSocketSecurityLevelTLSv1
                    forKey:NSStreamSocketSecurityLevelKey];

// After which you’ll want to retain the streams and open them


The key here is to set NSStreamSocketSecurityLevel appropriately. For almost all situations, NSStreamSocketSecurityLevelSSLv3 or NSStreamSocketSecurityLevelTLSv1 should be used. Unless, you’re writing a program where transport security just doesn’t matter (for example, a web crawler), SSLv2 or security negotiation should not be used.

Peer to Peer (P2P)

iPhone OS 3.0 introduced the ability to do P2P networking between devices via Bluetooth. Although technically part of the GameKit, the GKSession class is likely to be used by non-game applications as well, for collaboration and data exchange. This means that opportunities for data theft are increased. Also, because data can potentially be streamed to the device by a malicious program or user, we have another untrusted input to deal with.

GKSessions can behave in one of three different modes—client, server, or peer (a combination of client and server). The easiest way to interface to this functionality is through a GKPeerPickerController object, which provides a UI to allow the user to select from a list of peers. It should be noted, however, that using this controller is not required. This effectively allows an application to initiate or scan for a session without user interaction.

To find other devices (peers), a server device advertises its availability using its sessionID, while a client device polls for a particular ID. This session identifier can be specified by the developer, or, if it’s unspecified, it can be generated from the application’s App ID.

Because of the use of developer-specified sessionIDs and the ability to have background P2P activity, issues can arise where a developer uses a GKSession to advertise or scan in the background, pairing with any matching device that knows a shared sessionID. If sessionIDs are predictable, this means that the user’s device might be paired without their knowledge and against their will. This can lead to all manner of mischief.

In addition to simple Bluetooth connectivity, the GKVoiceChatService allows for full-duplex voice communication between devices. This is another connection that can be done without user interaction. To establish a voice connection with another device, another developer-specified identifier is needed, the participantID. Because an active pairing is already necessary for the use of Voice Chat, this ID can be a simple username or other symbolic name.

Here are the three main important security considerations when working with the GameKit:

image    Ensure that you use a unique identifier for the sessionID to avoid unwanted peering, and use the provided Picker API to let users explicitly accept connections.

image    Remember that GKSession remote connections supply untrusted data—sanity checks must be performed before operating on this data.

image    Use GKPeerPickerController to allow users to confirm connections.

Push Notifications, Copy/Paste, and Other IPC

In this section, we examine common methods for retrieving content from other applications or by third party services. The most prominent of these are “push notifications” and the UIPasteboard API.

Push Notifications

Also new in version 3.0, Apple has implemented the long-awaited “push notifications” feature, which allows applications to provide users with notifications when they are not running. To accomplish this, Apple has implemented its own web service callable by remote sites, relying on actual notification processing code to be run on a remote server. The device and push service perform mutual certificate authentication; developers using the push API also use certificates to authenticate with the API server. API certificates are bound to a particular application bundle ID, and must be stored on the server sending push notifications.

For example, the developer of a chat application would need to implement chat client functionality as a server process on a remote machine, sending messages to the Apple push notification API when a user receives a new message. Notification types can include pop-ups or incrementing a number next to a springboard icon. When the application is started, it queries the new data from the remote server.

This puts iPhone application developers in the role of web service providers, having to worry about scalability, web service security, and denial of service. Although this is largely outside the scope of this book, these are areas that developers wishing to implement push notifications should consider.

It should be noted that these messages are not guaranteed to be delivered; Apple’s servers will continue retrying for a fair bit of time, but the transport should not be considered to be reliable, and should not be used for transporting time-sensitive information or important data. In other words, this service should generally be used for sending notifications that new data is available, rather than only sending that data as part of the notification.

UIPasteboard

If you’ve written a desktop application on OS X, you may be familiar with the UIPasteboard object. UIPasteboards can be implemented to handle copying and pasting of objects within an application, or to handle data to share among applications. Copied and pasted data is stored in item groupings with various representations—that is, a single item can be portrayed in multiple ways. If, for example, you copy an image from a web page, you can copy both the image and the URL to its location into the same pasteboard item. The retrieving application can decide what data types it wants to receive from the pasteboard.

The two main system pasteboards are UIPasteboardNameGeneral and UIPasteboardNameFind. These are used for generic copying and pasting between applications and for storing search results, respectively. Developers can also create their own custom pasteboards, for private use by the application or to share data among related applications. This has been used as one method to migrate data from a free version of an application to a paid version, once the user has upgraded.

To use pasteboard data between application restarts, the developer can use the persistent pasteboard property. This will save out the pasteboard into the application’s directory upon exit, recovering it upon restart. Because this will be stored unencrypted on the iPhone’s file system, it’s important not to use pasteboard persistence in applications where sensitive data might be copied or pasted.

Here are some important considerations when dealing with UIPasteboards:

image    Use private pasteboards for data that is only needed by one application, or for data that may be sensitive. Check to see if your application ever displays data to the user that you wouldn’t want another application to see.

image    Use the persistent property sparingly. If sensitive data is selected and copied, it will be written to local storage, where someone who has gained illegitimate access can get to it.

image    Sanity-check pasteboard contents. Any information carried on shared pasteboards should be considered untrusted and potentially malicious; it needs to be sanitized before use.

image    Avoid complex parsing of this data.

Conclusion

The iPhone platform jumpstarted the entire smartphone industry, and its popularity is still going strong. The reliance on the App Store as the device’s primary security boundary is somewhat worrisome, which underscores the need for good programming practices and safe data storage.

With the increase of methods for iPhone applications to exchange data with each other, applications can no longer assume local inputs to be “safe.” Items such as pasteboard functionality and shared Keychains should be used cautiously. Several classic C attacks as well as client-side SQL injection attacks are possible in iPhone applications, but proper use of high-level APIs can drastically reduce these risks.

Development for the iPhone is not without its security pitfalls, but with the proper preparation, developing on the iPhone can be an enjoyable and (mostly) secure endeavor.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.106.9