Overview#
So far we have only examined whether or not apps are exported. For example, non-exported activities can’t be started and are used by the app internally - so we generally ignore these unless there is some intent redirect or pending intent we can see. So as a developer a very potent way to reduce the attack surface is to export as few components as possible - if it doesn’t need to be exported, don’t export it. There are however other cases where an app wants to export some activity, but only to some select applications and that is where the android permissions system comes into play.
Normal System Permissions#
One thing we saw when messing around with basic activities and intents was the Internet permission, where we had to declare it in the manifest with <uses-permission>
in order for the Android OS to let our app access the internet. The thing to keep in mind here is that not all permissions are made equal and some require user permissions and other don’t.
For example, normal permissions are defined as those that allow access to data and actions that extend past the sandbox of the application while still presenting little risk to the user’s privacy and the function of other apps. For this reason the OS will automatically grant these types of permissions to a requesting application at installation without asking for the user’s approval - although users can turn these off manually. So when we are making malicious apps for proof of concept exploits, we will typically consider any permissions as normal to be fair game and feasible. This is because it is less likely for a user to install a malicious app and explicitly grant a bunch of dangerous or sensitive permissions.
Dangerous Permissions#
These permissions are described as permissions that grant the requesting application access to private user data or some level of control over the device that can negatively impact the user. Dangerous permissions are often those presented to the user and will require some manual confirmation before using those permissions.
Security Boundaries of Permissions#
Most of the time so far we have been developing proof of concept exploit apps, so we need to know where the security boundaries are - mainly just understanding what kinds of permissions are considered reasonable for an attacker app to have. This isn’t an easy question to answer because it all really depends on the target - if we want a realistic threat model what kinds of permissions can be requested?
- The less permissions your attacking app requires, the better off you will be (makes sense right? less complexity = higher severity)
Imagine an app that can be used to install other apps using the INSTALL_PACKAGES
permission. It uses some exported activity to take an intent with a link to an APK when it then downloads that APK and installs it to the device. A malicious app in this context would just have to send an intent to this app that forces the installation of a malicious APK with no additional permissions required. Pretty straight forward, we would just chalk this up to a wrongly-exported intent.
Now, imagine that this same app requires the sender of the intent to have the MANAGE_EXTERNAL_STORAGE
, which is already a fairly high-on-the-chain permission because a user needs to go to the settings and manually enable this permission. In this case you shouldn’t assume that a malicious app can easily get access to this permission.
However, the ability to install other apps is very sensitive, so the argument could be made that because it is easier to get the external storage permissions than the package manager permissions - the severity is still relevant. This would be less severity than if the attacking app didn’t require permissions and the impact is greatly limited by the restriction, but the jump from file access to installing APKs is still a somewhat valid issue.
So, make sure that when you are making an attacker app that requires permissions that you are trying to exploit functionality of more sensitive permissions.
Protecting Components with Permissions#
When you look at the manifest, even if an activity is exported it may still have a permission configured that is required to call that activity. One example is the bind job service which lets the system bind to the application’s task services:
<service android:name="com.example.weather.SystemjobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true">
</service>
Whenever you see a component with a kind of permission attached to it, make sure you understand how that service works. In this case, the bind service is used in the work manager feature of android which is used to schedule jobs to be performed by the OS in the future. When it is time to execute the task the system connects to the exported service using the bind job service permission. The thing to keep in mind is that no other app can get the BIND_JOB_SERVICE
permission, so the attack surface here is minimal.
Imagine a weather application that uses the geo-location of a device to accurately display relevant weather information:
<service android:name="com.example.weather.WeatherService"
android:permission="android.permission.ACCESS_FINE_LOCATION"
android:exported="true">
</service>
Typically a user will just grant this permission and that will be the end of it, but what if this app wants to export a weather service for other apps to use. If that weather status data includes the location of the device that could be a vulnerability because other apps would be able to query the weather app and get the user’s location without having the ACCESS_FINE_LOCATION
permission. To mitigate this the weather app could require the permission be used by the calling app as shown above - this way only apps who already have that information can see the weather app data that would reveal the information.
Creating Custom Permissions#
Apps can actually also create their own custom permissions - for example let’s say you want to control which other apps can start a certain activity in your app, you can declare a permission for that like this:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp" >
<permission
android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
android:label="@string/permlab_deadlyActivity"
android:description="@string/permdesc_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous" />
...
</manifest>
The protectionLevel
attribute is always required and it tells the android OS how users ought to be informed when other apps request this permission. You might then later in the manifest define which activity uses this custom permission:
android:permission="com.example.myapp.permission.DEADLY_ACTIVITY"
Now, making your malicious app request this dangerous permission (from the user or otherwise) to then perform some dangerous action is not really a vulnerability, because this is how the OS intends this feature to work. However if there is a custom permission that is assigned a more relaxed protectionLevel
, then you might have a finding because the sensitive permission would no longer require user interaction.
Protected Broadcasts#
We have tried in the past to send protected broadcasts, like trying to send an airplane mode broadcast when only the system can send those. These are defined in the android core manifest, here are few broadcast actions that no regular app is allowed to send:
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
Common Issues#
We have kind of walked through permissions from a high level but we can just go briefly over what kinds of issues we might see in android applications. This list is based off of those provided on Oversecured.
- Poorly Attributed
protectionLevel
- Flawed Ecosystem Assumptions
- Typos in Declarations
- Insufficient Protection of Permissions
We have already gone over the poorly attributed protection levels. Flawed ecosystems would be like if an application is installed with the intent to have another app use it (in the same ecosystem). Imagine installing a social media app and another app that acts upon that other app’s activities and permissions. If the secondary app is installed in isolation, your malicious app could use any custom permissions that the secondary app is assuming will come from the trusted social media app.
Typos in permission names aren’t as common any more because newer APIs for android require the protection level to be set. Typos in the declaration of a component such as using android:uses-permission
instead of android:permission
will result in third party apps still being able to access the component.
Insufficient protection would be an instance where the permission is defined in the manifest properly, but is accessed in a way that doesn’t really protect those permissions. Imagine an app that reads the contacts, but has an exported provider that can be used to dump those contacts - the issue isn’t really the permission itself but more the fact that it isn’t safely isolated in the activity where it is used.
Other Reading#
I really enjoyed this talk from DEF CON 30 when going through and learning these things about permissions: