Intent Redirection Vulnerability

Risk: High - MASVS_CODE_4

Overview

An intent redirection occurs when an attacker can partly or fully control the contents of an intent used to launch a new component in the context of a vulnerable app.

The intent used to launch the new component can be supplied in several ways, most commonly either as a serialized intent in an extras field, or marshaled to a string and parsed. Partial control of parameters can also lead to the same result.

The Code: Intent Redirection Vulnerability

Here’s the code we’re analyzing:

Intent intent = getIntent();
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
        name.getClassName().equals("safe_class")) {
    // Redirect the nested intent.
    startActivity(forward);
}

Step-by-Step Explanation

  1. Receiving an External Intent:

    Intent intent = getIntent();

    The app receives an Intent from an external source.

  2. Extracting a Nested Intent:

    Intent forward = (Intent) intent.getParcelableExtra("key");

    The app extracts another Intent (called a nested intent) from the original Intent using the key "key".

  3. Resolving the Component of the Nested Intent:

    ComponentName name = forward.resolveActivity(getPackageManager());

    The code determines the Package Name and Class Name of the nested intent’s target component.

  4. Validating the Target Component:

    if (name.getPackageName().equals("safe_package") &&
         name.getClassName().equals("safe_class")) {

    It checks if the target package and class match the expected values (safe_package and safe_class).

  5. Redirecting the Nested Intent:

    startActivity(forward);

    If the validation passes, the app redirects the nested intent using startActivity().


Where is the Vulnerability?

The vulnerability lies in the validation logic.

  • The code only checks the package name and class name of the nested intent.

  • However, an attacker can craft a malicious nested intent that looks legitimate (safe_package and safe_class match) but contains harmful payloads.


Example of Exploiting the Vulnerability

An attacker can create an intent like this:

Intent maliciousIntent = new Intent();
Intent nestedIntent = new Intent();
nestedIntent.setComponent(new ComponentName("safe_package", "safe_class"));
// Add malicious data or actions
nestedIntent.putExtra("exploit_data", "malicious_data");
// Wrap the nested intent in the outer intent
maliciousIntent.putExtra("key", nestedIntent);
startActivity(maliciousIntent);

Here’s what happens:

  1. The outer intent contains a nested intent (nestedIntent).

  2. The nested intent’s ComponentName matches the expected values (safe_package and safe_class), so the validation passes.

  3. The app executes startActivity(forward) and processes the malicious payload inside the nested intent (exploit_data).

  4. If safe_class has a vulnerability or doesn’t properly validate the payload, the attack succeeds.


How to Mitigate the Vulnerability

As a rule of thumb, it's best to avoid exposing functionality related to redirecting nested intents. However, if the situation demands, use the following strategies for mitigation:

  • Check where the intent is being redirected.

  • Use PendingIntent objects. This prevents your component from being exported and makes the target action intent immutable.

  • Use IntentSanitizer to make a sanitized copy of an Intent

Apps can check where an intent is being redirected using methods such as ResolveActivity:

Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
        name.getClassName().equals("safe_class")) {
    // Redirect the nested intent.
    startActivity(forward);
}

Apps can use IntentSanitizer using logic similar to the following:

Intent intent = new  IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent);

Resources

Last updated

Was this helpful?