Android App Deep Link Abuse

Android utilizes a system known as Deep Links in order to perform navigation between the web and applications. For example when you open a Reddit or Twitter link on the web browser of your phone you'll often get a pop up asking if you want to open in the browser or the application (assuming you have it installed); this is facilitated by deep linking. This can also be done via inter-app communication, so one app can deep link to another.

iOS also offers this feature although this is called Universal Links and wont be the focus of this post, but are conceptually similar. This post primarily focuses on what Android deep links are, how they are defined, and most importantly how to abuse them.


Update 26/08/2020:

I've ported a lot of this content over to the OWASP Mobile Security Testing guide at:

Please also refer to this content when understanding deep links & app links on Android.


Consider the following example androidmanifest.xml code taken from the android developer documentation for creating deep links to app content:

This code is defining two similar Intents that operate as deep links, the only difference between this code is the <data> element which defines two different schemes. Schemes refer to the little code tidbit (otherwise known as a uniform resource identifier) at the front of a link, the https at the start of https://www.google.com for example.

This means that the following two URLs would have an effect of deep linking to the application:

  • http://www.example.com/gizmos
  • example://gizmos

When the user clicks these links this will result in the device launching the app activity that has defined these intents/deeplinks as shown above. If you don't know what an activity is, think of it as a screen within an android application; this page goes into more detail about what an activity is (a core concept of android applications).

Once this activity has been launched the developer then has the choice of programming what the intent actually does when called. The developer can call getIntent() in order to retrieve the Intent that started the activity and program how the application is going to handle this. Thus when reverse engineering you will want to be looking for this getIntent() method relative to the activity defined in the androidmanifest.xml file to find the entry point of the intent and understand how it handles the intent.

For more on the nitty gritty coding details of this refer to this android developer documentation.


Deep links are relatively simple, you make an intent that defines a scheme and the device will launch an activity in response to this being invoked. The application then has the choice of performing some action in response to this deep link / intent. There have been a number of public cases where deep links have been abused in order to perform attacks of varying severity, I've linked a couple of these for example here:

These findings demonstrate that there isn't a one stop cookie cutter way to abusing deep links, it depends on the particular application and how they have defined the deep link. It's important to understand the context of a deep link in order to understand how to abuse it. We can understand this context by decompiling the application and reverse engineering the activity to find the relevant getIntent() and the actions that it performs. For more information on decompiling and reverse engineering applications refer to this link.

In many cases what we really want to look out for is if the deep link accepts any user data. If this is the case then there is the possibility of performing attacks such as Cross Site Scripting (XSS) or Local File Inclusions depending on how the application handles the user data within the deep link.

An example of deep link abuse is that if the deep link accepts and reflects user data into a java script enabled web view then it would be entirely possible to perform reflected cross site scripting against the application with something like the following PoC code snippet:

<html>
<a href="example://gizmos?whatsmyname=mynameis<script>alert(1)</script>">This is my link</a>
</html>

For more general testing of deep links we can use the ADB Activity Manager in order to test the intent filter URIs. The syntax of the AM is fairly simple as shown:

  • adb shell am start -W -a android.intent.action.VIEW  -d <URI> <PACKAGE>

For example given the androidmanifest.xml file mentioned before we could test that example gizmos intent / deep link by doing the following command:

  • adb shell am start  -W  -a  android.intent.action.VIEW  -d "example://gizmos"  com.example.android

Now lets say for example that this gizmos application took in a user supplied parameter from the deep link and reflected it in a java script enabled web view just like in the PoC above; this could be tested using the following AM command:

  • adb shell am start -W -a  android.intent.action.VIEW  -d "example://gizmos?whatsmyname=mynameis<script>alert(1)</script>)"  com.example.android

And just like in the PoC this would give us a java script alert box indicating the possibility of cross site scripting.


Summary

The most important take away from this for attackers is that deep link vulnerabilities are very dependent on the application and require an understanding of how the application uses its deep links at a code level. Deep links themselves as a concept are not inherently vulnerable to attack (ignoring collision attacks), rather its their implementation by a developer that can make them vulnerable to attack.

In terms of securing deep links a developer always needs to consider that any data coming with a deep link is untrustworthy and needs to be handled as such. Furthermore it may be worth considering the usage of app links instead of deep links, which solves problems inherent to deep links such as URI collisions.


Further research / Sources: