Why is this an issue?
Intent redirection vulnerabilities occur when an application publicly exposes a feature that uses an externally provided intent to start a new
component.
In that case, an application running on the same device as the affected one can launch the exposed, vulnerable component and provide it with a
specially crafted intent. Depending on the application’s configuration and logic, this intent will be used in the context of the vulnerable
application, which poses a security threat.
What is the potential impact?
An affected component that forwards a malicious externally provided intent does so using the vulnerable application’s context. In particular, the
new component is created with the same permissions as the application and without limitations on what feature can be reached.
Therefore, an attacker exploiting an intent redirection vulnerability could manage to access a private application’s components. Depending on the
features privately exposed, this can lead to further exploitations, sensitive data disclosure, or even persistent code execution.
Information disclosure
An attacker can use the affected feature as a gateway to access other components of the vulnerable application, even if they are not exported. This
includes features that handle sensitive information.
Therefore, by crafting a malicious intent and submitting it to the vulnerable redirecting component, an attacker can retrieve most data exposed by
private features. This affects the confidentiality of information that is not protected by an additional security mechanism, such as an encryption
algorithm.
Attack surface increase
Because the attacker can access most components of the application, they can identify and exploit other vulnerabilities that would be present in
them. The actual impact depends on the nested vulnerability. Exploitation probability depends on the in-depth security level of the application.
Privilege escalation
If the vulnerable application has privileges on the underlying devices, an attacker exploiting the redirection issue might take advantage of them.
For example by crafting a malicious intent action, the attacker could be able to pass phone calls on behalf of the entitled application.
This can lead to various attack scenarios depending on the exploited permissions.
Persistent code execution
A lot of applications rely on dynamic code loading to implement a variety of features, such as:
- Minor feature updates.
- Application package size reduction.
- DRM or other code protection features.
When a component exposes a dynamic code loading feature, an attacker could use it during the redirection’s exploitation to deploy malicious code
into the application. The component can be located in the application itself or one of its dependencies.
Such an attack would compromise the application execution environment entirely and lead to multiple security threats. The malicious code could:
- Intercept and exfiltrate all data used in the application.
- Steal authentication credentials to third-party services.
- Change the application’s behavior to serve another malicious purpose (phishing, ransoming, etc)
Note that in most cases, the deployed malware can persist application or hosting device restarts.
How to fix it in Android
Code examples
This code is vulnerable to intent injection attacks because it starts a new activity from a user-provided intent without prior validation.
Noncompliant code example
public class Noncompliant extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
Intent forward = (Intent) intent.getParcelableExtra("anotherintent");
startActivity(forward); // Noncompliant
}
}
Compliant solution
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Intent forward = (Intent) intent.getParcelableExtra("anotherintent");
ComponentName name = forward.resolveActivity(getPackageManager());
if (name.getPackageName().equals("safePackage") &&
name.getClassName().equals("safeClass")) {
startActivity(forward);
}
}
}
How does this work?
In general, security best practices discourage forwarding intents. However, when the application requires such a feature, it should precisely check
the forwarded intents to ensure they do not pass malicious content.
Additionally, the components that are not meant to be accessed externally should be marked as non-exported in the application’s manifest. This is
done by setting the android:exported
attribute of the components to "false"
.
Checking the intent destination
Most unintended usage of the forwarding feature can be prevented by verifying whether the destination package and class names belong to a list of
accepted components.
The allow-list of accepted destinations should only contain components that perform non-sensitive actions and handle non-sensitive data. Moreover,
it should not allow reaching components that further redirect inner intents.
The example compliant code uses the resolveActivity
method of the inner intent to determine its target component. It then uses the
getPackageName
and getClassName
methods to validate this destination is not sensitive.
Checking the intent origin
Before forwarding the intent, the application can check its origin. Verifying the origin package is trusted prevents the forwarding feature from
being used by an external component.
The getCallingActivity
method of the forwarded intent can be used to determine the origin component.
Permissions downgrade
Before forwarding an intent to another component, the application can verify or remove the permissions set on the forwarded intent. In that case,
even if the destination is a sensitive component, the application can ensure the untrusted intent will not be able to read or write sensitive data or
locations.
In most cases, the application should drop the following permissions from untrusted intents:
- FLAG_GRANT_READ_URI_PERMISSION
- FLAG_GRANT_WRITE_URI_PERMISSION
Resources
Documentation
Standards