Custom Permissions

OWASP category: MASVS-CODE: Code Quality

Overview

The risks associated with Custom Permissions arise when either the custom permissions definition is missing or misspelled, or when the corresponding android:protectionLevel attribute is misused within the Manifest.

For example, these risks can be exploited by creating a custom permission with the same name, but defined by a malicious app and with different protection levels applied.

Custom permissions are designed to enable sharing resources and capabilities with other apps. Examples of a legitimate use of custom permissions could be the following:

  • Controlling inter-process communication (IPC) between two or more apps
  • Accessing third-party services
  • Restricting access to the shared data of an app

Impact

The impact of exploiting this vulnerability is that a malicious app could gain access to resources originally intended to be protected. The implications of the vulnerability depend on the resource being protected and the original application service's associated permissions.

Risk: Custom Permission Typos

A custom permission may be declared in the Manifest, but a different custom permission is used to protect exported Android components, due to a typo. A malicious application can capitalize on applications that have misspelled a permission by either:

  • Registering that permission first
  • Anticipating the spelling in subsequent applications

This can allow an application unauthorized access to resources or control over the victim application.

For example, a vulnerable app wants to protect a component by using a permission READ_CONTACTS but accidentally misspells the permission as READ_CONACTS. A malicious app can claim READ_CONACTS since it's not owned by any application (or the system) and gain access to the protected component. Another common variant of this vulnerability is android:permission=True. Values such as true and false, regardless of capitalization, are invalid inputs for the permission declaration and are treated similarly to other custom permission declaration typos. To fix this, the value of the android:permission attribute should be changed to a valid permission string. For example, if the app needs to access the user's contacts, the value of the android:permission attribute should be android.permission.READ_CONTACTS.

Mitigations

Android Lint Checks

When declaring custom permissions, use Android lint checks to help you find typos and other potential errors in your code.

Naming Convention

Use a consistent naming convention to make typos more noticeable. Carefully check the custom permission declarations in your app's Manifest for typos.


Risk: Orphaned Permissions

Permissions are used to guard resources of apps. There are two different locations where an app can declare the permissions required for accessing resources:

However, sometimes these permissions are not defined by a corresponding <permission> tag in a Manifest of an APK on the device. In this case, they are called orphaned permissions. This situation can occur for a number of reasons, such as:

  • There could be a desync between updates on the Manifest and the code with the permission check
  • The APK with the permissions might not be included in the build, or the wrong version could be included
  • The permission name in either the check or the Manifest could be spelled incorrectly

A malicious app could define an orphaned permission and acquire it. If this happens, then the privileged applications that trust the orphaned permission to protect a component could be compromised.

In cases where the privileged app uses the permission to protect or restrict any component, this could grant the malicious app access to that component. Examples include launching activities protected by a permission, accessing a content provider, or broadcasting to a broadcast receiver protected by the orphaned permission.

It could also create a situation where the privileged application is tricked into believing the malicious app is a legitimate app and therefore loading files or content.

Mitigations

Ensure that all custom permissions that your app uses to protect components are also defined in your Manifest.

The app uses the custom permissions my.app.provider.READ and my.app.provider.WRITE in order to protect access to a content provider:

Xml

<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>

The app also defines and uses these custom permissions, thus preventing other malicious apps from doing so:

Xml

<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />

Risk: Misused android:protectionLevel

This attribute describes the potential risk level in the permission and indicates what procedures the system should follow when deciding whether or not to grant the permission.

Mitigations

Avoid Normal or Dangerous Protection Level

Using a normal or dangerous protectionLevel on your permissions means most apps can request and get the permission:

  • "normal" requires only declaring it
  • "dangerous" will be approved by many users

Therefore, these protectionLevels provide little security.

Use Signature Permissions (Android >= 10)

Use signature protection levels wherever possible. Employing this capability ensures only other apps signed with the same certificate as the app that created the permission can access those protected features. Ensure you are using a dedicated (not reused) signing certificate and store it securely in a keystore.

Define a custom permission as follows in your Manifest:

Xml

<permission
    android:name="my.custom.permission.MY_PERMISSION"
    android:protectionLevel="signature"/>

Restrict the access to, e.g., an activity, to only those apps which have this custom permission granted, as follows:

Xml

<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>

Any other app that is signed with the same certificate as the app that declared this custom permission will then be granted access to the .MyActivity activity and needs to declare it as follows in its Manifest:

Xml

<uses-permission android:name="my.custom.permission.MY_PERMISSION" />

Beware of Signature Custom Permissions (Android < 10)

If your app targets Android < 10, then whenever your app's custom permissions are removed due to uninstalls or updates there could be malicious apps able to still use those custom permissions and thus bypassing checks. This is due to a privilege escalation vulnerability (CVE-2019-2200) which was fixed in Android 10.

This is one of the reasons (along with the risk of race conditions) why signature checks are recommended over custom permissions.


Risk: Race Condition

If a legitimate app A defines a signature custom permission that is used by other X apps but it is subsequently uninstalled, then a malicious app B can define that same custom permission with a different protectionLevel, e.g. normal. In this way, B gains access to all components protected by that custom permission in the X apps without any need to be signed with the same certificate as the app A.

The same happens if B gets installed before A.

Mitigations

If you would like to make a component only available to apps signed with the same signature as the providing app, you might be able to avoid defining custom permissions to restrict access to that component. In this situation you can use signature checks. When one of your apps makes a request for another of your apps, the second app can verify that both apps are signed with the same certificate before complying with the request.


Resources