Malicious iOS Apps

A comparison before and after iOS 8 was released

As part of one of our recent research projects, we evaluated how malicious third-party apps could affect user privacy, despite the various security controls and the solid security architecture of the iOS platform. Therefore, we reviewed the iOS app sandbox model for weaknesses – and, indeed, made some finds. Some of these defects, which Markus Troßbach and I disclosed to Apple a while back, have been addressed with yesterday’s release of iOS 8 (CVE-2014-4361, CVE-2014-4362).

Update (April 9th, 2015): Yesterday’s release of iOS 8.3 seems to fix some more of the below mentioned sandbox defects (CVE-2015-1113, CVE-2015-1115).


With iOS 8 the following deficiencies have been remedied:

  • Third-party apps can no longer readout a user’s Apple ID.
  • Third-party apps can no longer determine contact details of recently contacted persons.
  • Third-party apps can no longer monitor a user’s texting or messaging behavior, including details of persons contacted.
  • Third-party apps are no longer able to observe a user’s general app usage behavior, including the times and duration of both third-party and iOS-bundled system app usage.
  • Third-party apps can no longer secretly take pictures and transfer them off the device without user’s consent or knowledge.

However, the following issues are still present in iOS 8:

  • Third-party apps still can obtain a comprehensive list of the installed apps and the respective version numbers.
  • Third-party apps still can permanently monitor the iOS pasteboard for changes and read out any sensitive data that is probably copy-pasted.
  • ~~Third-party apps still can observe phone call metadata, such as precise call durations and the call recipients’ phone numbers~ (fixed in iOS 8.3, CVE-2015-1115).

Each of these points is explained in full detail below, followed by a conclusion at the end. Please note that all of the following defects could be exploited by third-party apps running on non-jailbroken iOS devices.

Unrestricted File System Access

To determine the effectiveness of the iOS sandbox mechanism with regard to file system access, we first extracted all file-read permissions from the container sandbox profile, which is applied to all third-party apps by default. While reviewing these sandbox rules, we noticed that several files within the general system preferences folder /private/var/mobile/Library/Preferences/ had been explicitly whitelisted, which makes their contents accessible to any third-party app. It turned out that within this folder particularly the following files disclosed personal data:


Within each of these files, we found the value of the key _im_ab_cache, reflecting contact details of recently contacted persons. Moreover, the file contained the SuspendedGroupID key, which discloses the contact details of the current receiving party within the iOS messages app. This means that any app can learn about a user’s texting or messaging behavior, including details of persons contacted, by only periodically querying this file.

Moreover, we found a single file system access sufficient to determine a user’s personal Apple ID. In more detail, we noticed that a user’s Apple ID could be retrieved from the file, even if the Home Sharing feature (which allows users to stream music and videos from their iTunes media library to other devices in their households) was not enabled at all. It turns out that the Apple ID is automatically stored to the Home Sharing configuration file when a user is successfully authenticated by any Apple service for the first time (when setting up iCloud, for example, or downloading apps from the App Store). Presumably, this was done to prepopulate the Apple ID value within the Home Sharing section of the iOS preferences app.

The privacy implications of this issue are numerous. Up to iOS 7, several hardware identifiers were available to allow apps to uniquely identify any iOS device. For instance, both the unique device identifier (UDID) and the hardware address of the WiFi module (WiFi MAC address) were frequently used by advertising or tracking networks to relate personal data or usage patterns to specific users. As this posed a major privacy threat, Apple removed access to those identifiers in iOS 7. Access to a user’s Apple ID, however, can be considered a much stronger identifier, as it allows not only the identification of a device, but also the identification of its owner. The advertising industry might, therefore, also have been interested in this method of reliably identifying users across apps.

A user’s Apple ID could also be used in phishing attacks from within third-party apps, in which criminals impersonate the official iTunes store authentication dialog that is displayed whenever users buy apps from the App Store or set up access to any Apple service. As the official iTunes sign-in dialog carries no special label to prove its authenticity, it can easily be imitated using default iOS alert view mechanisms (see Figure 1). It should be noted that the only identifying mark in the official iTunes dialog is the preset Apple ID value. This requirement could, however, easily be met using the Apple ID value from the Home Sharing configuration file. Using this personal value could increase users’ trust in these fake dialogs and could, in turn, increase the risk of users falling for phishing scams.

Impersonated iTunes Store Phishing Dialog leveraging a user's Apple ID.

Within iOS 8, the sandbox rules have been updated to disable access to the general system preferences folder for third-party apps.

Monitoring of Phone Connections

On iPhone devices, the Core Telephony framework can be used to obtain information about a user’s cellular service provider and the current cellular call status. Apps can, therefore, register with an event-driven interface provided by the CTCallCenter class to access information about state changes for calls. To enable this, apps must register a callback by assigning a handler block to the callEventHandler property. This handler is called by the iOS system whenever a call event takes place and is provided with a CTCall object. This object can then be used to determine a current call’s state as described in the following listing.

self.callCenter = [[CTCallCenter alloc] init];
self.callCenter.callEventHandler = ^(CTCall* call) {
    if (call.callState == CTCallStateConnected) {
        // Call is connected
    } else if (call.callState == CTCallStateDisconnected) {
        // Call is disconnected
    } else if (call.callState == CTCallStateIncoming) {
        // Call is incoming and has not yet been answered 
    } else if (call.callState == CTCallStateDialing) {
        // User is dialing a number

It should be noted that an app is supposed to receive these call state events only when it is in an active state and executing code. While this constraint would, at first glance, seem to lower the actual impact, the apps are not actually required to run in the foreground in order to receive information about call state changes. By abusing the iOS background execution and multitasking capabilities, apps can continue running in the background for an indefinite period of time (e.g., by playing a silent audio file in an endless loop). In consequence, this would allow any app that makes use of iOS’s multitasking features to monitor a user’s regular calling habits.

Further analysis revealed that apps may determine not only the times calls were initiated or received and their precise duration, but also the phone number of the called party. In order to do this, an app may leverage the private Telephony Utilities framework. The TUCallCenter class within this framework contains a reference to an instance of the TUTelephonyCall class (currentCalls selector). This, in turn, contains information on the current call, including its status and duration. Although invoking most of the methods provided by TUCallCenter would require certain entitlements, it turns out that the description selector, which returns a textual description of an object’s contents — and, in this particular case, the phone number of the current call — can be invoked without any special grants (the description selector is provided by the root class NSObject, a class from which the vast majority of all Objective-C classes inherit). As this instance demonstrates, iOS’s entitlement-based compartmentalization mechanism obviously fails to restrict access to protected resources in certain cases, particularly when interacting with parts of the Objective-C foundation.

Class TUCallCenter_class = objc_getClass("TUCallCenter");
NSObject* callCenter = [TUCallCenter_class performSelector:@selector(sharedInstance)];
NSArray* calls = [callCenter performSelector:@selector(currentCalls)];
for(NSObject* call in calls) {
    NSLog(@"call: %@", [call description]);

When used together, this combination of techniques allows any app to observe metadata on a user’s phone calls, including the call durations and the recipients’ phone numbers. The only requirement for this is an app running in the background, accessing functionality provided by a private API. From our and other researchers’ experiences, both requirements can easily be met, even for apps from the App Store.

These issues have not been fixed. Even in iOS 8, third-party apps can observe a user’s phone call behavior, including the precise call durations as well as the callers and recipients phone numbers.

General App Usage Behavior

When searching for further techniques to actively monitor users, we came across a method that allows any third-party app to observe the timing and duration of app usage. For this, we leveraged the SpringBoardServices framework to query information on the current frontmost running app. In general, this private framework allows users to invoke functions in the iOS SpringBoard via Mach messages. To make all the functions of the SpringBoardServices framework available, the dynamic linker is first instructed to load the corresponding dynamic library and to return the addresses of the required symbols (see listing below, based on a Stack Overflow post). After querying the SpringBoard server’s Mach port, the SBFrontmostApplicationDisplayIdentifier method is invoked to query the bundle identifier of the current frontmost running app.

void *lib = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
mach_port_t* ( *SBSSpringBoardServerPort)() = dlsym(lib,"SBSSpringBoardServerPort");
mach_port_t *port = (mach_port_t *)SBSSpringBoardServerPort();
void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) = dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
char appIdentifier[256];
memset(appIdentifier, 0, sizeof(appIdentifier));
SBFrontmostApplicationDisplayIdentifier(port, appIdentifier);
NSLog(@"frontmost app: %s", appIdentifier);

Through practical experiments, we verified that the SpringBoardServices can also be queried from apps running in the background. By repeatedly querying this method from a background app, we were able to determine the usage frequency and duration of both third-party and iOS-bundled system apps. This would allow any third-party app to gain detailed insights into a user’s general app usage.

Within iOS 8 this issue has been fixed. Third-party apps are therefore no longer able to observe a user’s general app usage habits.

Unrestricted Pasteboard Access

To allow users to exchange data within or between apps, iOS provides a “copy and paste” mechanism. A tap-and-hold Copy gesture advises the iOS system to write the selected items to a shared memory region known as the General pasteboard. Users can then choose to copy the cached pasteboard data (whether into the same app or into a different one), by using the same tap-and-hold gesture and choosing the Paste menu command.

From a privacy perspective, we found the following two problems with this pasteboard concept: 1. The general pasteboard contents can be accessed both via these gestures and menu commands, and programmatically from any app. The latter can be done without the user’s permission or knowledge. 2. The likelihood of such pasteboard compromises in iOS is increased by several factors, including the fact that even apps running in the background may periodically query the pasteboard to observe any content changes.

Although this is nothing new in general (particularly the first issue), such pasteboard stealing attacks might have been underestimated in the past, as users more and more use the pasteboard to even transfer sensitive data between apps.

For instance, during setup, the HotSpot Login App provided by Deutsche Telekom AG sends the user’s login data via text message. To make the overall setup process as convenient as possible, it instructs users to copy and paste the entire text message, including the username and password, to the app’s login fields. As the General pasteboard’s content is shared freely between apps, any rogue app can read the user’s access data from it.

Another instance in which sensitive data may end up on the iOS general pasteboard involves interaction with so-called “password manager” apps. These apps claim to secretly store confidential data such as passwords, PINs, bank and credit card information in an encrypted file, which is accessible only through a master password entered during app start. Once the secret data has been made available, however, it can simply be copied and pasted to another app.

Furthermore, apps like ScanPass Pro allow users to scan their (encrypted) passwords from printed QR codes. This should enable users to use complex passwords without worrying about mistyping them. A major drawback of this method, however, is that, after scanning the QR code, the app automatically places the (decrypted) password data, again, onto the general pasteboard for use in other apps.

Some password managers such as 1Password already try to limit exposure of sensitive data by clearing the pasteboard content after a certain period of time (so do enterprise apps also often clear the pasteboard contents on app suspend/close). These measures should prevent other apps - that are actively used in the meantime - to read out the cached pasteboard contents. However, such measures are completely ineffective against pasteboard stealing apps that are permanently running in the background.

Consequently, users should be aware that in iOS 8 third-party apps may still access the pasteboard without user’s consent and even apps running in the background are able to monitor the pasteboard for any content changes. Therefore, wouldn’t it be great if iOS would adopt known pasteboard concepts from the browser world and to allow access to the pasteboard only iff a user granted permission, either implicitly by using the copy/paste gesture commands or explicitly by answering a permission dialog, when an app tries to access the pasteboard programmatically? In addition, pasteboard access should generally be disabled for apps running in the background.

However, as long as this is not the case, it could be a good advise to be careful when using the iOS pasteboard mechanism, particularly when intended to transfer any sensitive data.

Installed Apps

A private method from the MobileCoreServices framework allows any app to query information on all the other apps available on a device. To obtain a comprehensive list of all the installed app names and the respective version numbers, an app must simply invoke the allApplications selector from the LSApplicationWorkspace class. It should be noted that the sample code described below will commonly not pass the App Store review process, as it directly invokes private API methods. As, however, we confirmed this part of the review process to be flawed in several aspects, a slight modification to this code would allow even App Store apps to invoke this private method (e.g., by dynamically instrumenting the Objective-C runtime).

Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
NSLog(@"apps: %@", [workspace performSelector:@selector(allApplications)]);

There are numerous possible uses for this information, many of which are, for obvious reasons, highly privacy-relevant. In keeping with the motto “Show me your apps and I’ll tell you who you are”, industries such as advertising might be extremely interested in this information. A list of installed apps would, for example, allow certain inferences to be drawn about users’ personal preferences. If a user installed a “baby monitor” app, for instance, plus an app to track a baby’s height, weight, sleep, etc., it would appear likely that the user was a parent and therefore particularly receptive to family-oriented content and advertising. And why not to deliver such tailored advertisements to users since we already know their Apple IDs?

One minor drawback of the aforementioned method is the invocation of private APIs. We therefore searched for alternative methods that rely solely on public APIs. We found out that the current sandbox rules allow read access to the folder /private/var/mobile/Library/Caches/ in which icons for all the installed apps are cached (see output below), presumably to be displayed on the iOS SpringBoard.

// System app icons[1]*[1]*[1]*[1]*[1]*[1]*[1]*[1]*[1]*[1]*[1]*
// Thid-party app icons[1]*[1]*

It turns out that the naming scheme for all files within this icon cache folder is based on an app’s bundle identifier, followed by the static string _CFBundleIcon. This allows any app to retrieve a list of installed apps by enumerating all the files in this folder and extracting the respective bundle identifier values.

These issues have not been fixed. Even in iOS 8, third-party apps can make use of both techniques to determine a list of installed apps.

Unrestricted Access to Camera Hardware

Finally, one of the most beneficial and long overdue privacy features in iOS 8 is probably the restriction to camera hardware. While iOS requested user permission for apps to use location services or the microphone for a long time, access to the camera hardware was still unrestricted in most countries (so far, iOS required users’ consent to access the camera only for devices sold in China). This allowed any app up to and including iOS 7 to use the front and/or rear-facing cameras to secretly take pictures at any time and to transfer them off the device without the user’s consent or knowledge. All methods required to access the camera hardware were provided by public methods from the AV Foundation framework and allowed any app to secretly take pictures programmatically, which means that no preview window was displayed on the screen (as is the case when UIImagePickerController is used) and no user consent was required (e.g., users do not need to tap a camera trigger button to take a picture).

This issue has been addressed in iOS 8 by introducing a new camera privacy control. When an app now tries to access the camera for the first time, the user is presented with a camera permission dialog.


While the iOS 8 sandbox has been revised to limit the ways in which third-party apps could surveil users, such as monitoring their texting or app usage behavior, some of the issues we reported are still present (e.g., determining installed apps, permantetely monitoring pasteboard content from within background apps, observing phone call metadata).

However, as practical exploitation of some of these issues require repeated invocation of certain APIs, which in turn requires an app to run in the background, it remains to be seen how effective iOS’s new „battery usage“ feature is. This feature promises to display battery usage by app in the iOS settings and to automatically shut down those that are draining too much battery power.

Now, notwithstanding any local sandbox defects, one could say that the App Store vetting process mainly serves as a second line of defense and therefore would never permit such malicious surveillance apps in the App Store… well, more on this later ;)