MOBILE APPLICATION SECURITY ON ANDROID

September 5, 2017 | Author: Berenice Peters | Category: N/A
Share Embed Donate


Short Description

1 MOBILE APPLICATION SECURITY ON ANDROID Context on Android security Black Hat 2009 This document describes the Android ...

Description

MOBILE APPLICATION SECURITY ON ANDROID Context on Android security

Black Hat 2009

This document describes the Android Security Model and provides the context required to understand the tools and techniques that will be demonstrated by Jesse Burns at his Black Hat USA talk, currently scheduled for July 30th, 2009. Updates are available on the iSEC Partners website. A developer’s guild to android is also maintained at that site, by the author at http://www.isecpartners.com/files/iSEC_Securing_Android_Apps.pdf.

Prepared for Black Hat USA by: Jesse Burns Questions: [email protected] Updates: https://www.isecpartners.com Date: June, 2009 Version 0.1

Introduction Android has a unique security model, which focuses on putting the user in control of the device. Android devices however, don’t all come from one place, the open nature of the platform allows for proprietary extensions and changes. These extensions can help or could interfere with security, being able to analyze a distribution of Android is therefore an important step in protecting information on that system. This document takes the reader through the security model of Android, including many of the key security mechanisms and how they protect resources. This background information is critical to being able to understand the tools Jesse will be presenting at Black Hat, and the type of information you can glean from the tools, and from any running Android distribution or application you wish to analyze. Before reading this paper you should already be familiar with Android’s basic architecture and major abstractions including: Intents, Activities, BroadcastReceivers, Services, ContentProviders and Binder1. If you haven’t yet encountered most of these platform features you might want to start with the Notepad2 tutorial. As Android is open source you should also have this code available to you. Both the java and C code is critical for understanding how Android works, and is far more detailed than any of the platform documentation. As will be discussed in the Black Hat talk, the difference between what the documentation and the source say is often critical to understanding the systems security.

The Android Security Model Android is a Linux platform programmed with Java and enhanced with its own security mechanisms tuned for a mobile environment3. Android combines OS features like efficient shared memory, preemptive multi-tasking, Unix user identifiers (UIDs) and file permissions with the type safe Java language and its familiar class library. The resulting security model is much more like a multi-user server than the sandbox found on the J2ME or Blackberry platforms. Unlike in a desktop computer environment where a user’s applications all run as the same UID, Android applications are individually siloed from each other. Android applications run in separate processes under distinct UIDs each with distinct permissions. Programs can typically neither read nor-write each other’s data or code,4 and sharing data between applications must be done explicitly. The Android GUI environment has some novel security features that help support this isolation. Mobile platforms are growing in importance, and have complex requirements5 including regulatory compliance6. Android supports building applications that use phone features while protecting users by minimizing the consequences of bugs and malicious software. Android’s process isolation obviates the need for complicated policy configuration files for sandboxes. This gives applications the flexibility to use native code without compromising Android’s security or granting the application additional rights. 1

Binders are a bit of an advanced topic. We will introduce them in the Services section. http://code.google.com/android/intro/tutorial.html 3 Cylon heritage is perhaps the most problematic security aspect of Android’s lineage. 4 Hence getting code execution on most Android application doesn’t fully compromise the device! 5 Like the need to support emergency calling, even on screen-locked or out of service phones. 6 Government regulations vary widely so the platform needs a lot of flexibility. 2

Black Hat USA 2009

Page 2

Android permissions are rights given to applications to allow them to do things like take pictures, use the GPS or make phone calls. When installed, applications are given a unique UID, and the application will always run as that UID on that particular device. The UID of an application is used to protect its data and developers need to be explicit about sharing data with other applications7. Applications can entertain users with graphics, play music, and launch other programs without special permissions. Malicious software is an unfortunate reality on popular platforms, and through its features Android tries to minimize the impact of malware. However, even unprivileged malware that gets installed on an Android device (perhaps by pretending to be a useful application) can still temporarily wreck the user’s experience8. Users in this unfortunate state will have to identify and remove the hostile application. Android helps users do this, and minimizes the extent of abuse possible, by requiring user permission for programs that do dangerous things like: – directly dialing calls (which may incur tolls), – disclosing the user’s private data, or – destroying address books, email, etc. Generally a user’s response to annoying, buggy or malicious software is simply to uninstall it. If the software is disrupting the phone enough that the user can't uninstall it, they can reboot the phone (optionally in safe mode9, which stops non-system code from running) and then remove the software before it has a chance to run again.

Security Responsibilities of Developers Developers writing for Android need to consider how their code will keep users safe as well as how to deal with constrained memory, processing and battery power. Developers must protect any data users input into the device with their application, and not allow malware to access the application’s special permissions or privileges. How to achieve this is partly related to which features of the platform an application uses, as well as any extensions to the platform an Android distribution has made. One of the trickiest big-picture things to understand about Android is that every application runs with a different UID. Typically on a desktop every user has a single UID and running any application launches runs that program as the users UID. On Android the system gives every application, rather than every person, its own UID. For example, when launching a new program (say by starting an Activity), the new process isn’t going to run as the launcher but with its own identity. It’s important that if a program10 is launched with bad parameters11 the developer of that application has ensured it won’t harm the system or do something the phone’s user didn’t intend. Any program can ask Activity Manager to launch almost any other application, which runs with the application’s UID.

7

This paper will cover how to safely do such sharing. Android offers several flexible mechanisms to choose from. For example they could play loud noises, interrupt the user or run down the battery. 9 How to enter safe mode is device specific. One prototype platform required holding the Menu button while booting. 10 By programs what is usually meant is an Activity or a Service. This will be covered in more detail later. 11 Android applications don’t usually have parameters — there isn’t even a UI to specify them in the Home application. 8

Black Hat USA 2009

Page 3

Fortunately, the untrusted entry points to your application are limited to the particular platform features you choose to use and are secured in a consistent way. Android applications don’t have a simple main function that always gets called when they start. Instead, their initial entry points are based on registering Activites, Services, BroadcastReceivers or ContentProviders with the system. After a brief refresher on Android Permissions and Intents we will cover securely using each of these features. Android requires developers to sign their code. Android code signing usually uses self-signed certificates, which developers can generate without anyone else’s assistance or permission. One reason for code signing is to allow developers to update their application without creating complicated interfaces and permissions. Applications signed with the same key (and therefore by the same developer) can ask to run with the same UID. This allows developers to upgrade or patch their software easily, including copying data from existing versions. The signing is different than normal Jar or Authenticode12 signing however, as the actual identity of the developer isn’t necessarily being validated by a third party to the device’s user13. Developers earn a good reputation by making good products; their certificates prove authorship of their works. Developers aren’t trusted just because they paid a little money to some authority. This approach is novel, and may well succeed, but it wouldn’t be technically difficult to add trusted signer rules or warnings to an Android distribution if it proved desirable.

Android Permissions Review Applications need approval to do things their owner might object to, like sending SMS messages, using the camera or accessing the owner’s contact database. Android uses manifest permissions to track what the user allows applications to do. An application’s permission needs are expressed in its AndroidManifest.xml and the user agrees to them upon install14. When installing new software, users have a chance to think about what they are doing and to decide to trust software based on reviews, the developer’s reputation, and the permissions required. Deciding up front allows them to focus on their goals rather than on security while using applications. Permissions are sometimes called ―manifest permissions‖ or ―Android permissions‖ to distinguish them from file permissions. To be useful, permissions must be associated with some goal that the user understands. For example, an application needs the READ_CONTACTS15 permission to read the user’s address book. A contact manager app needs the READ_CONTACTS permission, but a block stacking game shouldn’t16. Keeping the model simple, it’s possible to secure the use of all the different Android inter-process communication (IPC) mechanisms with just a single kind of permission. Starting Activities, starting or 12

Authenticode is a popular Microsoft code signing technology documented here: http://msdn.microsoft.com/enus/library/ms537364(VS.85).aspx. They usually identify a company and are validated by a certificate authority. 13 Some mobile platforms use code signing as a way to control and track developers. Android’s self-signing system just makes software easier to maintain and use. Certificate chains and the standards third parties used to validate identities are too complex for most users to understand, so Android uses a more social approach to developer identity. 14 The same install warnings are used for side loaded and Market applications. Applications installed with adb don’t show warnings but that mechanism is only used by developers. The future may bring more installers than these three. 15 ―android.permission.READ_CONTACTS‖ is the permission’s full text. 16 If the game vibrates the phone, or connects to a high score Internet server it might need VIBRATE or INTERNET permission.

Black Hat USA 2009

Page 4

connecting to Services, accessing ContentProviders, sending and receiving broadcast Intents, and invoking Binder interfaces can all require the same permission. Therefore users don’t need to understand more than ―My new contact manager needs to read contacts‖.

Developer Tip: Users won’t understand how their device works, so keep permissions simple and avoid technical terms like Binder, Activity or Intent when describing permissions to users.

Once installed, an application’s permissions can’t be changed. By minimizing the permissions an application uses it minimizes the consequences of potential security flaws in the application and makes users feel better about installing it. When installing an application, users see requested permissions in a dialog similar17 to the one shown in Figure 1. Installing software is always a risk and users will shy away from software they don’t know, especially if it requires a lot of permissions.

17

The dialog lists permissions; the installation dialog gives a bit more information and the option to install as well.

Black Hat USA 2009

Page 5

Figure 1 Dialog showing Application permissions to users. (Chu, 2008)

From a developer’s perspective permissions are just strings associated with a program and its UID. You can use the Context class’ checkPermission(String permission, int pid, int uid) method to programmatically check if a process (and the corresponding UID) has a particular permission like READ_CONTACTS18. This is just one of many ways permissions are exposed by the runtime to developers. The user view of permissions is simple and consistent; the idiom for enforcement by developers is consistent too but adjusts a little for each IPC mechanism. Figure 2 shows an example permission definition. Note that the description and label are resources to aid in localizing the application.

Figure 2 Custom permission definition in an AndroidManifest.xml file. Manifest permissions like the one above have a few key properties. Two text descriptions are required: a short text label, and a longer description used on installation. An icon for the permission can also be provided (but isn’t in the example above). All permissions must also have a name which is globally unique. The name is the identifier used by programmers for the permission and is the first parameter to Context.checkPermission. Permissions also have a protection level (called protectionLevel as shown above). There are only four protection levels for permissions19: Normal

Dangerous

Signature

SignatureOrSystem

Permissions for application features whose consequences are minor like VIBRATE which lets applications vibrate the device. Suitable for granting rights not generally of keen interest to users, users can review but may not be explicitly warned. Permissions like WRITE_SETTINGS or SEND_SMS are dangerous as they could be used to reconfigure the device or incur tolls. Use this level to mark permissions users will be interested in or potentially surprised by. Android will warn users about the need for these permissions on install. These permissions can only be granted to other applications signed with the same key as this program. This allows secure coordination without publishing a public interface. Similar to Signature except that programs on the system20 image also qualify for access. This allows programs on custom Android systems to also get the permission. This protection is to help integrate system builds and won’t typically be needed by developers.

Figure 3 Android manifest permission protection levels

If you try to use an interface which you don’t have permissions for you will probably receive a SecurityException. You may also see an error message logged indicating which permission you need to enable. If your application enforces permissions you should consider logging an error on failure so that

19

See http://code.google.com/android/reference/android/R.styleable.html#AndroidManifestPermission_protectionLevel or search for ―Android Manifest Permission protectionLevel‖ for platform documentation. 20 Of course custom system builds can do whatever they like; indeed you ask the system when checking permissions – but SignatureOrSystem level permissions intend for third party integration and so protects more stable interfaces then Signature.

Black Hat USA 2009

Page 7

developers calling your application can more easily diagnose their problems. Sometimes (aside from the lack of anything happening) permission failures are silent. The platform itself neither alerts users when permission checks fail, nor allows granting of permissions to applications after installation. Developer Tip: Your application might be used by people who don’t speak your language. Be sure to internationalize the label and description properties of any new permission you create. Have someone both technical and fluent in the target languages review to ensure translations are accurate.

In addition to reading and writing data, many permissions allow applications to call upon system services or start Activities with security sensitive results. For example, with the right permission a video game can take full control of the screen and obscure the status bar, or a dialer can cause the phone to dial a number without prompting the user.

Creating New Manifest Permissions Applications can define their own permissions if they intend other applications to have programmatic access to them. Using a manifest permission allows the end user to decide which programs get access, rather than having the developer just assume access is acceptable. For example, an application that manages a shopping list application could define a permission named ―com.isecpartners.ACCESS_SHOPPING_LIST‖ (ACCESS_SHOPPING_LIST for short). If the application defines an exclusive ShoppingList object then there is now precisely one instance of ShoppingList and the ACCESS_SHOPPING_LIST permission is needed to access it. The permission would be required for callers trying to see or update the shopping list. Done correctly, only the programs that declare they use this permission could access the list, giving the user a chance to either consent or prevent inappropriate access. When defining permissions keep them clear and simple, make sure you actually have a service or some data you want to expose not to just interactive users but to other programs. Adding permissions should be avoided using a little cleverness whenever possible. For example you could define an Activity that added a new item to the shopping list. When an application called startActivity and provided an Intent to add a new shopping list item, the Activity could display the data provided and ask for confirmation from the user instead of requiring permission enforcement. This keeps the system simple for users and saves you development effort. A requirement for Activities that immediately altered the list upon starting would make the permission approach necessary. Creating custom permissions can also help you minimize the permission requirements for applications that use your program programmatically. For example, if an application needs permissions to both send SMS messages and access the users location,21 it could define a new permission like

21

Location determination can require multiple permissions depending on which scheme the particular phone uses.

Black Hat USA 2009

Page 8

―SEND_LOCATION_MESSAGE‖. This permission is all that applications using your service would need, making their installation simpler and clearer to the user.

Black Hat USA 2009

Page 9

Intents Intents are an Android-specific mechanism for moving data between Android processes and are at the core of much of Android’s IPC. They don’t enforce security policy themselves, but are usually the messenger that crosses the actual system security boundaries. To allow their communication role Intents can be sent over Binder interfaces (since they implement the Parcelable interface). Almost all Android IPC is actually implemented through Binder, although most of the time this is hidden from us with higher level abstractions.

Intent Review Intents are used in a number of ways by Android:  

  

To start an Activity – coordinating with other programs like browsing a web page o Using Context’s startActivity() method. As broadcasts to inform interested programs of changes or events o Using Context’s sendBroadcast(), sendStickyBroadcast(), and sendOrderedBroadcast() family of methods. As a way to start, stop or communicate with background Services o Using Context’s startService(), stopService(), and bindService() methods To access data through ContentProviders, such as the user’s contacts. o Using Context’s getContentResolver() or Activities managedQuery() As call backs to handle events, like returning results or errors asynchronously with PendingIntents provided by clients to servers through their Binder interfaces

Intents have a lot of implementation details22, but the basic idea is that they represent a blob of serialized data that can be moved between programs to get something done. Intents usually have an action, which is a string like ―android.intent.action.VIEW‖ that identifies some particular goal, and often some data in the form of a Uri23. Intents can have optional attributes like a list of Categories, an explicit type (independent of what the data’s type is), a component, bit flags and a set of name value pairs called ―Extras‖. Generally APIs that take Intents can be restricted with manifest permissions. This allows you to create Activities, BroadcastReceivers, ContentProviders or Services that can only be accessed by applications the user has granted these rights to.

Intent Filters Depending on how they are sent, Intents may be dispatched by the Android Activity Manager. For example an Intent can be used to start an Activity by calling Context.startActivity(Intent intent). The Activity to start is found by Android’s Activity Manager by matching the passed in Intent against the IntentFilters registered for all Activities on the system and looking for the best match. Intents can

22 23

Indeed the documentation for just the Intent class is far longer than this document. An instance of the android.net.Uri class.

Black Hat USA 2009

Page 10

override the IntentFilter match Activity Manager uses however. Any ―exported‖24 Activity can be started with any Intent values for action, data, category, extras, etc. The IntentFilter is not a security boundary from the perspective of an Intent receiver. In the case of starting an Activity, the caller decides what component is started and creates the Intent the receiver then gets. The caller can choose to ask Activity Manger for help with figuring out where the Intent should go, but doesn’t have to. Intent recipients like Activities, Services and BroadcastReceivers need to handle potentially hostile callers, and an IntentFilter doesn’t filter a malicious Intent25. IntentFilters help the system figure out the right handler for a particular Intent, but doesn’t constitute an input filtering system. Because IntentFilters are not a security boundary they cannot be associated with permissions. While starting an Activity is the example I used to illustrate this above, you will see in the following sections that no IPC mechanisms using IntentFilters can rely on them for input validation. Categories can be added to Intents, making the system more selective about what code the Intent will be handled by. Categories can also be added to IntentFilters to permit Intents to pass, effectively declaring that the filtered object supports the restrictions of the Category. This is useful whenever you are sending an Intent whose recipient is determined by Android, like when starting an Activity or broadcasting an Intent. Developer Tip: When starting or broadcasting Intents where an IntentFilter is used by the system to determine the recipients, remember to add as many categories as correctly apply to the Intent. Categories often require promises about the safety of dispatching an Intent, helping stop the Intent from having unintended consequences. Adding a category to an Intent restricts what it can do. For example an IntentFilter that has the ―android.intent.category.BROWSABLE‖ category is indicating it is safe to be called from the web browser. Carefully consider why Intents would have a category and consider if you have met the terms of that contract before placing a category in an IntentFilter. Future categories could (for example) indicate an Intent was from a remote machine or un-trusted source but because this category won’t match the IntentFilters we put on our applications today, the system won’t deliver them to our programs. This keeps our applications from behaving unexpectedly when the operating environment changes in the future.

24

An activity is automatically exported if it has an IntentFilter specified, it can also be exported explicitly by adding the attribute android:exported=‖true‖ 25 You can enforce a permission check for anyone trying to start an Activity however. This is explained in the section on Activities.

Black Hat USA 2009

Page 11

Activities Activities allow applications to call each other, reusing each other’s features, and allowing for replacements or improvement of individual system pieces whenever the user likes. Activities are often26 run in their own process, running as their own UID, and so don’t have access to the caller’s data aside from any data provided in the Intent used to call the Activity. Developer Tip: The easiest way to make Activities safe is just to confirm any changes or actions clearly with the user. If starting your Activity with an Intent27 could result in harm or confusion you need to require a permission to start it. Activities cannot rely on IntentFilters (the tag in AndroidManifest.xml) to stop callers from passing them badly configured Intents. Misunderstanding this is actually a relatively common source of bugs. On the other hand, Activity implementers can rely on permission checks as a security mechanism. Setting the android:permission attribute in an declaration will prevent programs lacking the specified permission from directly starting that Activity. Specifying a manifest permission that callers must have doesn’t make the system enforce an intent-filter or clean intents of unexpected values so always validate your input. This code shows starting an Activity with an Intent. The Activity Manager will likely decide to start the web browser to handle it, because the web browser has an Activity registered with a matching intentfilter.

Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse("http://www.isecpartners.com")); this.startActivity(i);

Figure 4 Starting an Activity based on its IntentFilter

The following code demonstrates forcing the web browser’s Activity to handle and Intent with an action and data setting that aren’t permitted by its intent-filter:

// The browser's intent filter isn't interested in this action

26

Activities implemented by the caller’s program may share a process, depending on configuration.

27

An Intent received by an Activity is essentially untrusted input and must be carefully and correctly validated.

Black Hat USA 2009

Page 12

Intent i = new Intent("Cat-Farm Aardvark Pidgen"); // The browser's intent filter isn't interested in this Uri scheme i.setData(Uri.parse("marshmaellow:potatochip?")); // The browser activity is going to get it anyway! i.setComponent(new ComponentName("com.android.browser", "com.android.browser.BrowserActivity")); this.startActivity(i);

Figure 5 Starting an Activity regardless of its IntentFilter

If you run this code you will see the browser Activity starts, but the browser is robust and aside from being started just ignores this weird Intent. Figure 6 gives an example AndroidManifest entry that declares an Activity called ―.BlankShoppingList‖. This example Activity clears the current shopping list and gives the user an empty list to start editing. Because clearing is destructive, and happens without user confirmation, this Activity must be restricted to trustworthy callers. The ―com.isecpartners.ACCESS_SHOPPING_LIST‖ permission allows programs to delete or add items to the shopping list, so programs with that permission are already trusted not to wreck our list. The description of that permission also explains to users that granting it gives an applications the ability to read and change shopping lists. We protect this Activity with the following entry: I





Figure 6 Activity declaration requiring a caller permission.

When defining Activities, those defined without an intent-filter or an android:exported attribute are not publicly accessible, that is, other applications can’t start them with Context.startActivity(Intent intent). These Activities are the safest of all, but other applications won’t be able to reuse your application’s Black Hat USA 2009

Page 13

Activities. Developers need to be careful not just when implementing Activities but when starting them too. Avoid putting data into Intents used to start Activities that would be of interest to an attacker. A password, sensitive Binder or message contents would be prime examples of data not to include! For example Malware could register a higher priority IntentFilter and end up getting the user’s sensitive data sent to their Activity instead. When starting an Activity if you know the component you intend to have started, you can specify that in the Intent by calling its setComponent() method. This prevents the system from starting some other Activity in response to your Intent. Even in this situation it is still unsafe28 to pass sensitive arguments in this Intent. You can think of the Intent used to start an Activity as being like the command line arguments of a program, which usually shouldn’t include secrets either.

Developer Tip: Don’t put sensitive data into Intents used to start Activities. Callers can’t easily require Manifest permissions of the Activities they start, and so your data might be exposed.

28

For example processes with the GET_TASKS permission are able to see ―ActivityManager.RecentTaskInformation‖ which includes the ―baseIntent‖ used to start Activities.

Black Hat USA 2009

Page 14

Broadcasts Broadcasts are a way applications and system components can communicate securely and efficiently. The messages are sent as Intents, and the system handles dispatching them, including starting receivers, and enforcing permissions.

Receiving Broadcast Intents Intents can be broadcast to BroadcastReceivers, allowing messaging between applications. By registering a BroadcastReceiver in your application’s AndroidManifest.xml you can have your application’s receiver class started and called whenever someone sends you a broadcast. Activity Manager uses the IntentFilters applications register to figure out which program to use for a given broadcast. As we discussed in the sections on IntentFilters and Activity permissions, filters are not a security mechanism and can’t be relied upon29 by Intent recipients. As with Activities, a broadcast sender can send a receiver an Intent that would not pass its IntentFilter just by specifying the target receiver component explicitly30. Receivers must be robust against unexpected Intents or bad data. As always in secure IPC programming, programs must carefully validate their input. BroadcastRecievers are registered in the AndroidManifest.xml with the tag. By default they are not exported, but can be exported easily by adding an tag (including an empty one) or by setting the attribute android:exported=“true”. Once exported, receivers can be called by other programs. Like Activities, the Intents that BroadcastReceivers get may not match the IntentFilter they registered. To restrict who can send your receiver an Intent use the android:permission attribute on the receiver tag to specify a manifest permission. When a permission is specified on a receiver, Activity Manager validates that the sender has the specified permission before delivering the Intent. Permissions are the right way to ensure your receivers only gets Intents from appropriate senders, but permissions don’t otherwise affect the properties of the Intent that will be received.

Safely Sending Broadcast Intents When sending a broadcast, developers include some information or sometimes even a sensitive object like a Binder. If the data being sent is sensitive they will need to be careful who it gets sent to. The simplest way to protect this while leaving the system very dynamic is to require the receiver to have a permission. By passing a manifest permission name (receiverPermission is the parameter name) to one of Context’s broadcastIntent() family of methods you can require recipients to have that permission. This lets developers control which applications can receive the Intent. Broadcasts are special in being able to very easily require permissions of recipients; when you need to send sensitive messages prefer this IPC mechanism.

29

IntentFilters can sometimes help Intent sender safety by allowing the sending of an Intent that is qualified by a category. Receivers that don’t meet the category requirements won’t receive it, unless the sender forces delivery by specifying a component. Senders adding categories to narrow deliver therefore shouldn’t specify a Component. 30 See the examples given for Activities in the Activity Permissions section. These examples can be applied to broadcasts by using sendBroadcast() rather than startActivity() and adjusting the components appropriately for your test classes.

Black Hat USA 2009

Page 15

For example, an SMS application might want to notify other interested applications of an SMS it received by broadcasting an Intent. It can limit the receivers to those applications with the RECEIVE_SMS permission by specifying this as a required permission when sending. If an application sent the contents of an SMS message on to other applications by broadcasting an Intent without asserting that the receiver must have the RECEIVE_SMS permission then unprivileged applications could register to receive that Intent — creating a security hole. Applications can register to receive Intents without any special privileges. Therefore, applications must require that potential receivers have some relevant permission before sending off an Intent containing sensitive data.

Developer Tip: It is easier to secure implementing Activities than BroadcastReceivers because Activities can ask the user before acting. However, it is easier to secure sending a broadcast than starting an Activity because broadcasts can assert a manifest permission the receiver must have.

Stick Broadcasts Sticky broadcasts are usually informational and designed to tell other processes some fact about the system state. Sticky broadcasts stay around after they have been sent, and also have a few funny security properties. Applications need a special privilege, BROADCAST_STICKY, to send or remove a sticky Intent. You can’t require a permission when sending a sticky broadcast, so don’t use them for exchanging sensitive information! Also anyone else with BROADCAST_STICKY can remove a sticky Intent you create, so consider that before trusting them to persist. Developer Tip: Avoid using sticky broadcasts for sharing sensitive information, since they can’t be secured like other broadcasts can.

Black Hat USA 2009

Page 16

Services Services are long running background processes provided by Android to allow for background tasks like music playing or running of a game server. They can be started with an Intent and optionally communicated with over a Binder interface by calling Context’s bindService() method31. Services are similar to BroadcastReceivers and Activities in that they can be started independently of their IntentFilters by specifying a Component (if they are exported). Services can also be secured by adding a permission check to their tag in the AndroidManifest.xml. The long lasting connections provided by bindService() create a fast IPC channel based on a Binder interface (see below). Binder interfaces can check permissions on their caller, allowing them to enforce more than one permission at a time or different permissions on different requests. Services therefore provide lots of ways to make sure the caller is trusted, similar to Activities, BroadcastReceivers and Binder interfaces. Calling a Service is slightly trickier. This hardly matters for scheduling MP3s to play, but if you need to make sensitive calls into a Service, like storing passwords or private messages, you’ll need to validate the Service you’re connect to is the correct one and not some hostile program32 that shouldn’t have access to the information you provide. If you know the exact component you are trying to connect to, you can specify that explicitly in the Intent you use to connect. Alternately, you can verify it against the name provided to your SeviceConnection’s onServiceConnected(ComponentName name, IBinder service) implementation. That isn’t very dynamic though and doesn’t let users choose to replace the service provider. To dynamically allow users to add replacement services, and then authorize them by means of checking for the permission they declared and were granted by the user we can use the component name’s package33 as a way to validate a permission. We received the name of the implementing component when we receive the onServiceConnected() callback, and this name is associated with the applications rights. This is perhaps harder to explain than to do and comes down to only a single line of code! res = getPackageManager().checkPermission(permToCheck, name.getPackageName());

Figure 7 Checking a package has a permission Compare the result of the checkPermission() call shown above with the constants PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED. As documented the returned value is an integer, not a boolean.

31

This is a slight oversimplification, but by using bindService() you can eventually get a binder channel to talk with a Service. 32 An old attack on many IPC mechanisms is to ―name-squat‖ on the expected IPC channel or name. Attackers listen on a port, name, etc. that trusted programs use to talk. Clients therefore end up talking to the wrong server. 33 Also available to your ServiceConnection’s onServiceConnected(ComponentName name, IBinder binder) method.

Black Hat USA 2009

Page 17

ContentProviders Android has the ContentProvider mechanism to allow applications to share raw data. This can be implemented to share SQL data, images, sounds or whatever you like; the interface is obviously designed to be used with a SQL backend and one is even provided. ContentProviders are implemented by applications to expose their data to the rest of the system, the tag in the applications AndroidManifest.xml registers a provider as available and defines permissions for accessing it. The Android security documentation mentions that there can be separate read and write permissions for reading and writing on a provider ―…holding only the write permission does not mean you can read from a provider…‖ (Google Inc., 2008). People familiar with SQL will probably realize that it isn’t generally possible to have write-only SQL queries. For example an updateQuery() or deleteQuery() call results in the generation of a SQL statement in which a where clauses is provided by the caller. This is true even if the caller has only write permission. Controlling a where clause doesn’t directly return data, but the ability to change a statement’s behavior based on the stored data value effectively reveals it. Through watching the side effects of a series of calls with clever where clauses, callers can slowly reconstruct whatever data is stored34. You could certainly create a provider for which this was not the case, especially if the provider is file or memory based, but it isn’t likely that this will just work for simple SQL based providers. Keep this in mind before relying on write-only provider access. Declare the read and write permissions you wish enforced by the system directly in the AndroidMainfext.xml’s tag. These tags are android:readPermission and android:writePermission. These permissions are enforced at access time, subject to the limitations of the implementations discussed above. A general permission tag needed for any access can also be required.

Developer Tip: Assume clients with write access to a content provider also have read access. Describe any write permission you create as granting read-write access to SQL based providers.

Implementing a provider that is shared with other applications involves accepting some risks. For example, will those other applications properly synchronize their accesses of the data, and send the right notifications on changes? ContentProviders are very powerful, but you don’t always need all that power. Consider simpler ways of coordinating data access where convenient. An advanced feature providers may use is dynamic granting and revoking of access to other programs. The programs granted access are identified by their package name, which is the name they registered with the system on install (in their tags, android:package attribute). Packages are granted

34

Attackers exploiting ―blind‖ SQL injection flaws use this technique for flaws that don’t directly expose query results.

Black Hat USA 2009

Page 18

temporary access to a particular Uri. Generally, granting this kind of access doesn’t seem like a great idea though as the granting isn’t directly validated by the user, and there may not be correct restrictions on the query strings the caller can use. I also haven’t worked with this option enough to give advice about using it securely35. It can be used by marking your provider tag with the attribute android:grantUriPermissions=―true‖, and a subsequent 36 with attributes specifying which Uri’s are permitted. Providers may then use grantUriPermission() and revokeUriPermission() methods to give add and remove permissions dynamically. The right can also be granted with special Intent flags: FLAG_GRANT_READ_URI_PERMISSION, and FLAG_GRANT_WRITE_URI_PERMISSION. Code doing this kind of thing would be a great place to start looking for security holes.

Avoiding SQL injection To avoid SQL injection requests need to clearly delineate between the SQL statement and the data it includes. If data is misconstrued to be part of the SQL statement the resulting SQL injection can have difficult to understand consequences, from harmless bugs that annoy users to serious security holes that expose a user’s data. SQL injection is easily avoided on modern platforms like Android by using parameterized queries which distinguish data from query logic explicitly. The ContentProivder’s query(), update(), delete() and Activities’ managedQuery() methods all support parameterization. These methods all take the ―String[] selectionArgs‖ parameter, a set of values that get substituted into the query string in place of ―?‖ characters, in the order the question marks appear. This provides clear separation between the content of the SQL statement in the ―selection‖ parameter, and the data being included. If the data in selectionArgs contains characters otherwise meaningful in SQL, the database still won’t be confused. You may also wish to make all your selection strings final in order to avoid accidentally contaminating them with user input that could lead to SQL injection. SQL injection bugs in data input directly by the end user are likely to annoy users when they input friends whose name contains SQL meta-characters such as the single quote or apostrophe. A SQL injection could occur wherever data is received and then used in a query, that means data from callers of Binder interfaces, or data in Intents received from a broadcast, Service or Activity invocation, and these would be potential targets for malware to attempt to exploit. Always be careful about SQL injection, but consider more formal reviews of code where data for a query is from remote sources (RSS feeds, web pages, etc.). If you use parameterized types for all values you refer to and never use string concatenation to generate your SQL, you can avoid it completely.

35

Expect an update to this paper with details on using this securely, or send me your tips.

36

See the rather weak documentation for this here: http://code.google.com/android/reference/android/R.styleable.html#AndroidManifestGrantUriPermission

Black Hat USA 2009

Page 19

Intent Reflection A common idiom when communicating on Android is to receive a callback via an Intent. For an example of this idiom in use you could look at the Location Manager, which is an optional service. The Location Manager is a binder interface with the method LocationManager.addProximityAlert(). This method takes a PendingIntent, which lets callers specify how to notify them. Such callbacks can be used any time, but occur especially frequently when engaged in IPC via an Activity, Service, BroadcastReceiver or Binder interface using Intents. If your program is going to send an Intent when called, you need to avoid letting a caller trick you into sending an Intent they wouldn’t be allowed to. I call getting someone else to send an Intent for you ―intent reflection‖, and preventing it is a key use of the android.app.PendingIntent class which was introduced in Android SDK 0.9. If your application exposes an interface allowing its caller to be notified by receiving an Intent, you should probably change it to accept a PendingIntent instead of an Intent. PendingIntents are sent as the process that created them. The server making the callback can be assured that what they send will be treated as coming from the caller and not from themselves. This shifts the risk from the service to the caller. The caller now needs to trust the service with the ability to send this Intent as itself, which shouldn’t be hard as they control the Intent’s properties. The documentation for PendingIntent wisely recommends locking the PendingIntent to the particular component it was designed to send the callback to with setComponent(). This controls the Intent’s dispatching.

Black Hat USA 2009

Page 20

Files and Preferences UNIX-style file permissions are present in Android for file-systems which are formatted to support them, such as the root file system. Each application has its own area on the file system which it owns almost like programs have a home directory to go along with their user ids. An Activity or Service's Context object gives access to this directory with the getFilesDir(), getDir(), openFileOutput(), openFileInput(), getFileStreamPath(), methods but the files and paths returned by the context are not special and can be used with other file management objects like FileInputStream. The mode parameter is used to create a file with a given set of file permissions (corresponding to the UNIX file permissions). You can bitwise-OR these permissions together. For example, a mode of MODE_WORLD_WRITABLE | MODE_WORLD_READABLE makes a file world-readable37 and writable. The value MODE_PRIVATE cannot be combined this way as it is just a zero. Somewhat oddly the mode parameter also indicates if the resultant file is truncated or opened for appending– with MODE_APPEND. Figure 8 is a simple example of creating an example file that can be read by anyone. fos = openFileOutput("PublicKey", Context.MODE_WORLD_READABLE);

Figure 8 Creating a World Readable file to write a public key into The resultant FileOutputStream (called fos above) can be written to only by this process, but read by any program on the system should you wish to share it. This interface of passing in flags that indicate files are world-readable or world-writable is simpler than the file permissions Linux supports but should be sufficient for most applications38. Generally any code that creates data that is world accessible must be carefully reviewed to consider: 

Is anything written to this file sensitive?39



Could a change to this data cause something unpleasant or unexpected to happen? o Is the data in a complex format whose native parser might have exploitable vulnerabilities?40



If world-writeable, do you understand that a bad program could fill up the phones memory and your application would get the blame?41

37

World is also known as other, so MODE_WORLD_WRITEABLE creates other writeable files, like the command ―chmod o+w somefile‖ does. 38 To experiment with full Linux file permissions you could try executing chmod, or the ―less documented‖ android.os.FileUtils class’s static method setPermissions(), which takes a filename, a mode uid and gid. 39 For example something you only know because of a permission you have. 40 Historically a lot of complex file format parsers written in C or C++ have had exploitable parser bugs. 41 This kind of anti-social behavior might happen. Because the file is stored under your application’s home directory, the user might choose to fix the problem by uninstalling your program or wiping its data.

Black Hat USA 2009

Page 21

Obviously executable code like scripts, libraries or configuration files that specify which components, sites or folders to use would be bad candidates for allowing writes. Log files, databases or pending work would be bad candidates for world readability. SharedPreferences is a system feature that is backed by a file with permissions like any others. The mode parameter for getSharedPreferences(String name, int mode) uses the same file modes defined by Context. It is very unlikely you have preferences so unimportant you don’t mind if other programs change them. I recommend avoiding using MODE_WORLD_WRITEABLE, and suggest searching for it when reviewing an application as an obvious place to start looking for weaknesses.

Mass Storage Android devices are likely to have a limited amount of memory on the internal file system. Some devices may support larger add on file systems mounted on memory cards however. For example, the emulator supports this with the –sdcard parameter, and it is referenced repeatedly in Android’s documentation. Storing data on these file systems is a little tricky. To make it easy for users to move data back and forth between cameras, computers and Android, the format of these cards is VFAT. VFAT is an old standard that doesn’t support the access controls of Linux, so data stored here is unprotected. You should inform users that bulk storage is shared with all the programs on their device, and discourage them from putting really sensitive stuff there. If you need to store confidential data you can encrypt it, and store the tiny little key42 in the application’s file area, and the big ciphertext on the memory card. As long as the user doesn’t want to use the storage card to move the data onto another system this should work. You may need to provide some mechanism to decrypt the data and communicate the key to the user if they wish to use the memory card to move confidential data between systems.

42

A tiny 128 bit key is actually very strong. You can probably generate it at random as users will never need to see it. But think about the implications for backups before trying this.

Black Hat USA 2009

Page 22

Binder Interfaces Binder is a kernel device driver that uses Linux’s shared memory feature to achieve efficient, secure IPC. System services are published as Binder interfaces and the AIDL (Android Interface Definition Language) is used not just to define system interfaces, but to allow developers to create their own Binder clients and servers. The terminology can be confusing, but servers generally subclass android.os.Binder and implement the onTransact() method while clients receive a binder interface as an android.os.IBinder reference and call its transact() method. Both transact() and onTransact() use instances of android.os.Parcel43 to exchange data efficiently. Android’s support for Binder includes the interface Parcelable. Parcelable objects can be moved between processes through a Binder. Under the covers, a Binder reference is a descriptor maintained by the Binder device (which is a kernel mode device driver). Binder IPC can be used to pass and return primitive types, Parcelable objects, file descriptors (which also allows memory maps), and Binders. Having a reference to a binder interface allows calls to its interface (i.e. call transact() and have a corresponding call to onTransact() occur on the server side) — but does not guarantee that the service exposing the interface will do what the caller requests. For example, any program can get a reference to the Zygote system service’s Binder and call the method on it to launch an application as some other user, but Zygote will ignore such requests from unauthorized processes. Binder security has two key ways it can enforce security: by checking the caller’s identity, and by Binder reference security.

Security by Caller Permission or Identity Checking When a Binder interface is called, the identity of the caller is securely provided by the kernel. Android associates the calling application’s identity44 with the thread on which the request is handled. This allows the recipient to use their Context’s checkCallingPermission(String permission) or checkCallingPermissionOrSelf(String permission) methods to validate the caller’s rights. Applications commonly want to enforce permissions they don’t have on callers and so checkCallingPermissionOrSelf(String permission) allows the application to still call itself even if it lacks the normally needed permission. Binder services are free to make other binder calls, but these calls always occur with the services own identity (UID and PID) and not the identity of the caller. Binder services also have access to the callers identity using the getCallingUid() and getCallingPid() static methods of the Binder class. These methods return the UID and process identifier (PID) of the process which made the Binder call. The identity information is securely communicated to the implementer of a Binder interface by the kernel45.

43

The native implementation of this Parcel formats data as it is expected by the kernel mode Binder device.

44

The application’s UID, and its process’s current PID are provided.

45

This is similar to how UNIX domain sockets can tell you the identity of the caller, or most IPC mechanisms on win32.

Black Hat USA 2009

Page 23

A Binder interface can be implemented a number of ways. The simplest is to use the AIDL compiler to create a Stub class which you then subclass. Inside the implementations of the methods the caller is automatically associated with the current thread so calling Binder.getCallingUid() identifies the caller. Developers who direct requests to handlers or implement their own onTransact() (and forego AIDL) must realize the identity of the caller is bound to the thread the call was received upon and so must be determined before switching to a new thread to handle a request. A call to Binder.clearCallingIdentity() will also stop getCallingUid() and getCallingPid() from identifying the caller. Context’s checkPermission(String permission, int pid, int uid) method is useful for performing permission checks even after the callers identity has been cleared by using the stored UID and PID values.

Binder Reference Security Binder references can be moved across a Binder interface. The Parcel.writeStrongBinder() and Parcel.readStrongBinder() methods allow this and provide some security assurances. When reading a binder reference from a Parcel with readStrongBinder() the receiver is assured (by the kernel’s binder driver) that the writer of that binder had a reference to the received binder reference. This prevents callers from tricking servers by sending guesses of the numerical value used in the server’s process to represent a Binder the caller doesn’t have. Getting a reference to a Binder46 isn’t always possible. Because servers can tell if callers had a particular binder, not giving out references to a Binder can effectively be used as a security boundary. While Zygote might not protect its binder interfaces from exposure, many Binder objects are kept private. To use reference security, processes need to carefully limit the revealing of Binder objects. Once a process receives a Binder it can do whatever it likes with it, passing it to others or calling its transact() method. Binders are globally unique, which means if you create one nobody else can create one that appears equal to it. A Binder doesn't need to expose an interface, it might just serve as a unique value. A Binder can be passed between cooperating processes. A service could provide callers a Binder which acts as a key, knowing that only those who receive the key (or had it sent to them) could later send it back. This acts like an unguessable, easily generated password. The Activity Manager uses the reference nature of Binders to control management of Surfaces and Activities.

46

By Binder, I mean a reference to a binder interface. When programming in Java these are represented by an android.os.Binder object.

Black Hat USA 2009

Page 24

Conclusion Android applications have their own identity enforced by the system. Applications can communicate with each other using system provided mechanisms like files, Activities, Services, BroadcastReceivers, and ContentProviders. If you use one of these mechanisms you need to be sure you are talking to the right entity — you can usually validate it by knowing the permission associated with the right you are exercising. If you are exposing your application for programmatic access by others, make sure you enforce permissions so that unauthorized applications can’t get the user’s private data or abuse your program. Make your applications security as simple and clear as possible. When communicating with other programs, think clearly about how much you can trust your input, and validate the identity of services you call. Before shipping, think about how you would patch a problem with your application. A note on ―root‖ access: code with root access, like knives or fire, is both useful and dangerous. Obviously some system processes like the Zygote need root to do their jobs. You have probably found that on the emulator it is easy to become root (su, adb shell, etc.) but Android distributions trying to slow recovery of data from lost phones or meet government regulations might not allow this. You may find yourself needing root access, for example to create some super encrypted and compressed virtual memory feature. This sort of thing is easy for custom builds of Android, running on emulators. Turning on security is actually a feature of an Android distribution. If the SystemProperty ―ro.secure‖ is not set to 1, then the platform makes little effort at security. As much fun as it is to run Android on an emulator though, many developers will want their custom builds to work on phones too. For this a development platform47 or a hardware platform with a friendly bootloader48 that will let you load your code is needed. This background information should be sufficient for you to be able to understand the presentation I will be making at Black Hat USA. It also includes most of the information provided in my developers guide for creating secure Android applications. Understanding Android application security is the starting point, not the end point for being able to understand Android distribution security. The tools I am presenting will help us look at whole distributions, and proprietary extensions to understand what we are dealing with and the security issues they

47

OpenMoko is open, although porting hasn’t been done as of this writing.

48

A bootloader is the code that a device uses to start. Some loaders attempt to prevent the loading of custom software, this helps you feel better if you lost a phone that had personal data on it – but also inhibits deployment of custom builds.

Black Hat USA 2009

Page 25

Acknowledgements This material is based on the developers guide the author published in 2008, shortly after the opensourcing of the Android platform. Acknowledgements to the people that helped in writing that are given in the guild, which is maintained at http://www.isecpartners.com/files/iSEC_Securing_Android_Apps.pdf. I would also like to thank Black Hat USA, which is providing the venue for the release of my tools and my presentation of on Android internals and security.

Android Terminology Activity – A screen that a user interacts with. When you create an Android application the default is to create an Activity for it. Android’s ―hello world‖ program uses an single Activity. Activity Manager – A system program that manages Activitys, Receivers, Services, low memory conditions, as well as some IPC dispatching. Its Binder is available through getSystemService(String). AIDL – Android Interface Definition Language, an object oriented interface description language that makes it easy to communicate over Binders between processes. Optimized for Java but workable in C. AndroidManifest.xml – A main file every application uses to define itself to the system. The starting point for Android security where Activities, BroadcastReceivers, Services, ContentProviders, permissions and the need for permissions are all declared. Binder – This is a real thing in your address space, it has a unique identity and is known about by the underlying OS. If you make one and I make one they aren’t identical, if I send you mine and you send it back I can tell that it isn’t some other Binder even though they don’t have little names on them. You can use a Binder to talk between processes, or as an unforgeable token. Linux – The famous Linux kernel. Used by Android and extended to support Binder and friends at http://git.android.com. Parcelable – An interface that allows something to be put in a Parcel. This interface is usually needed to send an object over a Binder interface. Intents and Bundles are two common Parcelable classes. Permission – The right to do something. There are many ways of expressing permissions; Android introduces Manifest Permissions which take up a few pages in this paper. Reference Security – Capabilities is one notion of how security can be implemented by passing unforgeable tokens that represent authority around. Binders are references that can be used this way. Side Loading – Direct user installation of applications, for example a website with an .APK users can directly install from the browser. Note that self-signed certificates don’t prevent active network attackers from changing the code, so always install over SSL!

Black Hat USA 2009

Page 26

Works Cited Chu, E. (2008, August 28). Android Market: a user-driven content distribution system. Retrieved August 30, 2008, from Android Developer's Blog: http://androiddevelopers.blogspot.com/2008/08/android-market-user-driven-content.html Google Inc. (2008, August 29). Security and Permissions in Android. Retrieved August 30, 2008, from Android - An Open Handset Alliance Project: http://code.google.com/android/devel/security.html Burns, Jesse (2009, October) D EVELOPING SECURE MOBILE APPLICATIONS FOR ANDROID. http://www.isecpartners.com/files/iSEC_Securing_Android_Apps.pdf

Black Hat USA 2009

Page 27

View more...

Comments

Copyright � 2017 SILO Inc.