mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Renamed to AndroidIntentRedirection
Added qhelp
This commit is contained in:
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
|
||||||
<qhelp>
|
|
||||||
<overview>
|
|
||||||
<p></p>
|
|
||||||
</overview>
|
|
||||||
<recommendation>
|
|
||||||
<p></p>
|
|
||||||
</recommendation>
|
|
||||||
<example>
|
|
||||||
<p></p>
|
|
||||||
<sample src="" />
|
|
||||||
</example>
|
|
||||||
<references>
|
|
||||||
<li>
|
|
||||||
<a href=""></a>
|
|
||||||
</li>
|
|
||||||
</references>
|
|
||||||
</qhelp>
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>An exported Android component that obtains a user-provided Intent and uses it to launch another component
|
||||||
|
can be exploited to obtain access to private, unexported components of the same app or to launch other apps' components
|
||||||
|
in behalf of the victim app.</p>
|
||||||
|
</overview>
|
||||||
|
<recommendation>
|
||||||
|
<p>Do not export compontents that start other components from a user-provided Intent.
|
||||||
|
They can be made private by setting the `android:exported` property to `false` in the app's Android Manifest.</p>
|
||||||
|
<p>If this is not possible, restrict either which apps can send Intents to the affected component, or which components can be started from it.</p>
|
||||||
|
</recommendation>
|
||||||
|
<example>
|
||||||
|
<p>The following snippet contains two examples.
|
||||||
|
In the first example, an arbitrary component can be started from the externally provided `forward_intent` Intent.
|
||||||
|
In the second example, the destination component of the Intent is first checked to make sure it is safe.</p>
|
||||||
|
<sample src="AndroidIntentRedirectionSample.java" />
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
<li>
|
||||||
|
Google:
|
||||||
|
<a href="https://support.google.com/faqs/answer/9267555?hl=en">Remediation for Intent Redirection Vulnerability</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
OWASP Mobile Security Testing Guide:
|
||||||
|
<a href="https://mobile-security.gitbook.io/mobile-security-testing-guide/android-testing-guide/0x05a-platform-overview#intents">Intents</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Android Developers:
|
||||||
|
<a href="https://developer.android.com/guide/topics/manifest/activity-element#exported">The `android:exported` attribute</a>.
|
||||||
|
</li>
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* @name Android Intent redirect
|
* @name Android Intent redirection
|
||||||
* @description xxx
|
* @description Starting Android components with user-provided Intents
|
||||||
|
* can provide access to internal components of the application,
|
||||||
|
* increasing the attack surface and potentially causing unintended effects.
|
||||||
* @kind path-problem
|
* @kind path-problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @security-severity xx
|
* @security-severity 7.5
|
||||||
* @precision high
|
* @precision high
|
||||||
* @id java/android/unsafe-android-webview-fetch
|
* @id java/android/intent-redirection
|
||||||
* @tags security
|
* @tags security
|
||||||
* external/cwe/cwe-926
|
* external/cwe/cwe-926
|
||||||
* external/cwe/cwe-940
|
* external/cwe/cwe-940
|
||||||
@@ -13,10 +15,10 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.security.AndroidIntentRedirectQuery
|
import semmle.code.java.security.AndroidIntentRedirectionQuery
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, IntentRedirectConfiguration conf
|
from DataFlow::PathNode source, DataFlow::PathNode sink, IntentRedirectionConfiguration conf
|
||||||
where conf.hasFlowPath(source, sink)
|
where conf.hasFlowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"Arbitrary Android activities or services can be started from $@.", source.getNode(),
|
"Arbitrary Android activities or services can be started from $@.", source.getNode(),
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// BAD: A user-provided Intent is used to launch an arbitrary component
|
||||||
|
Intent forwardIntent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
|
startActivity(forwardIntent);
|
||||||
|
|
||||||
|
// GOOD: The destination component is checked before launching it
|
||||||
|
Intent forwardIntent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
|
ComponentName destinationComponent = forwardIntent.resolveActivity(getPackageManager());
|
||||||
|
if (destinationComponent.getPackageName().equals("safe.package") &&
|
||||||
|
destinationComponent.getClassName().equals("SafeClass")) {
|
||||||
|
startActivity(forwardIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GOOD: The component that sent the Intent is checked before launching the destination component
|
||||||
|
Intent forwardIntent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
|
ComponentName originComponent = getCallingActivity();
|
||||||
|
if (originComponent.getPackageName().equals("trusted.package") && originComponent.getClassName("TrustedClass")) {
|
||||||
|
startActivity(forwardIntent);
|
||||||
|
}
|
||||||
@@ -5,26 +5,26 @@ private import semmle.code.java.dataflow.DataFlow
|
|||||||
private import semmle.code.java.frameworks.android.Intent
|
private import semmle.code.java.frameworks.android.Intent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sink for Intent redirect vulnerabilities in Android,
|
* A sink for Intent redirection vulnerabilities in Android,
|
||||||
* that is, method calls that start Android components (like activities or services).
|
* that is, method calls that start Android components (like activities or services).
|
||||||
*/
|
*/
|
||||||
abstract class IntentRedirectSink extends DataFlow::Node { }
|
abstract class IntentRedirectionSink extends DataFlow::Node { }
|
||||||
|
|
||||||
/** A sanitizer for data used to start an Android component. */
|
/** A sanitizer for data used to start an Android component. */
|
||||||
abstract class IntentRedirectSanitizer extends DataFlow::Node { }
|
abstract class IntentRedirectionSanitizer extends DataFlow::Node { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A unit class for adding additional taint steps.
|
* A unit class for adding additional taint steps.
|
||||||
*
|
*
|
||||||
* Extend this class to add additional taint steps that should apply to `IntentRedirectConfiguration`.
|
* Extend this class to add additional taint steps that should apply to `IntentRedirectionConfiguration`.
|
||||||
*/
|
*/
|
||||||
class IntentRedirectAdditionalTaintStep extends Unit {
|
class IntentRedirectionAdditionalTaintStep extends Unit {
|
||||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default sink for Intent redirect vulnerabilities. */
|
/** Default sink for Intent redirection vulnerabilities. */
|
||||||
private class DefaultIntentRedirectSink extends IntentRedirectSink {
|
private class DefaultIntentRedirectionSink extends IntentRedirectionSink {
|
||||||
DefaultIntentRedirectSink() {
|
DefaultIntentRedirectionSink() {
|
||||||
exists(MethodAccess ma, Method m |
|
exists(MethodAccess ma, Method m |
|
||||||
ma.getMethod() = m and
|
ma.getMethod() = m and
|
||||||
this.asExpr() = ma.getAnArgument() and
|
this.asExpr() = ma.getAnArgument() and
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
/** Provides taint tracking configurations to be used in Android Intent Redirect queries. */
|
/** Provides taint tracking configurations to be used in Android Intent redirection queries. */
|
||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
import semmle.code.java.dataflow.TaintTracking
|
import semmle.code.java.dataflow.TaintTracking
|
||||||
import semmle.code.java.security.AndroidIntentRedirect
|
import semmle.code.java.security.AndroidIntentRedirection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taint tracking configuration for user-provided Intents being used to start Android components.
|
* A taint tracking configuration for user-provided Intents being used to start Android components.
|
||||||
*/
|
*/
|
||||||
class IntentRedirectConfiguration extends TaintTracking::Configuration {
|
class IntentRedirectionConfiguration extends TaintTracking::Configuration {
|
||||||
IntentRedirectConfiguration() { this = "IntentRedirectConfiguration" }
|
IntentRedirectionConfiguration() { this = "IntentRedirectionConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof IntentRedirectSink }
|
override predicate isSink(DataFlow::Node sink) { sink instanceof IntentRedirectionSink }
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||||
sanitizer instanceof IntentRedirectSanitizer
|
sanitizer instanceof IntentRedirectionSanitizer
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
any(IntentRedirectAdditionalTaintStep c).step(node1, node2)
|
any(IntentRedirectionAdditionalTaintStep c).step(node1, node2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,50 +5,50 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
public class AndroidIntentRedirectTest extends Activity {
|
public class AndroidIntentRedirectionTest extends Activity {
|
||||||
AndroidIntentRedirectTest(Context base) {
|
AndroidIntentRedirectionTest(Context base) {
|
||||||
super(base);
|
super(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
{
|
{
|
||||||
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
startActivities(new Intent[] {intent}); // $ hasAndroidIntentRedirect
|
startActivities(new Intent[] {intent}); // $ hasAndroidIntentRedirection
|
||||||
startActivities(new Intent[] {intent}, null); // $ hasAndroidIntentRedirect
|
startActivities(new Intent[] {intent}, null); // $ hasAndroidIntentRedirection
|
||||||
startActivity(intent); // $ hasAndroidIntentRedirect
|
startActivity(intent); // $ hasAndroidIntentRedirection
|
||||||
startActivity(intent, null); // $ hasAndroidIntentRedirect
|
startActivity(intent, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityAsUser(intent, null); // $ hasAndroidIntentRedirect
|
startActivityAsUser(intent, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityAsUser(intent, null, null); // $ hasAndroidIntentRedirect
|
startActivityAsUser(intent, null, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityAsCaller(intent, null, false, 0); // $ hasAndroidIntentRedirect
|
startActivityAsCaller(intent, null, false, 0); // $ hasAndroidIntentRedirection
|
||||||
startActivityAsUserFromFragment(null, intent, 0, null, null); // $ hasAndroidIntentRedirect
|
startActivityAsUserFromFragment(null, intent, 0, null, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResult(intent, 0); // $ hasAndroidIntentRedirect
|
startActivityForResult(intent, 0); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResult(intent, 0, null); // $ hasAndroidIntentRedirect
|
startActivityForResult(intent, 0, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResult(null, intent, 0, null); // $ hasAndroidIntentRedirect
|
startActivityForResult(null, intent, 0, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResultAsUser(intent, null, 0, null, null); // $ hasAndroidIntentRedirect
|
startActivityForResultAsUser(intent, null, 0, null, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResultAsUser(intent, 0, null, null); // $ hasAndroidIntentRedirect
|
startActivityForResultAsUser(intent, 0, null, null); // $ hasAndroidIntentRedirection
|
||||||
startActivityForResultAsUser(intent, 0, null); // $ hasAndroidIntentRedirect
|
startActivityForResultAsUser(intent, 0, null); // $ hasAndroidIntentRedirection
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
startService(intent); // $ hasAndroidIntentRedirect
|
startService(intent); // $ hasAndroidIntentRedirection
|
||||||
startServiceAsUser(intent, null); // $ hasAndroidIntentRedirect
|
startServiceAsUser(intent, null); // $ hasAndroidIntentRedirection
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
|
||||||
sendBroadcast(intent); // $ hasAndroidIntentRedirect
|
sendBroadcast(intent); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcast(intent, null); // $ hasAndroidIntentRedirect
|
sendBroadcast(intent, null); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcast(intent, null, null); // $ hasAndroidIntentRedirect
|
sendBroadcast(intent, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcast(intent, null, 0); // $ hasAndroidIntentRedirect
|
sendBroadcast(intent, null, 0); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcastAsUser(intent, null); // $ hasAndroidIntentRedirect
|
sendBroadcastAsUser(intent, null); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcastAsUser(intent, null, null); // $ hasAndroidIntentRedirect
|
sendBroadcastAsUser(intent, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcastAsUser(intent, null, null, null); // $ hasAndroidIntentRedirect
|
sendBroadcastAsUser(intent, null, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcastAsUser(intent, null, null, 0); // $ hasAndroidIntentRedirect
|
sendBroadcastAsUser(intent, null, null, 0); // $ hasAndroidIntentRedirection
|
||||||
sendBroadcastAsUserMultiplePermissions(intent, null, null); // $ hasAndroidIntentRedirect
|
sendBroadcastAsUserMultiplePermissions(intent, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendStickyBroadcast(intent); // $ hasAndroidIntentRedirect
|
sendStickyBroadcast(intent); // $ hasAndroidIntentRedirection
|
||||||
sendStickyBroadcastAsUser(intent, null); // $ hasAndroidIntentRedirect
|
sendStickyBroadcastAsUser(intent, null); // $ hasAndroidIntentRedirection
|
||||||
sendStickyBroadcastAsUser(intent, null, null); // $ hasAndroidIntentRedirect
|
sendStickyBroadcastAsUser(intent, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendStickyOrderedBroadcast(intent, null, null, 0, null, null); // $ hasAndroidIntentRedirect
|
sendStickyOrderedBroadcast(intent, null, null, 0, null, null); // $ hasAndroidIntentRedirection
|
||||||
sendStickyOrderedBroadcastAsUser(intent, null, null, null, 0, null, null); // $ hasAndroidIntentRedirect
|
sendStickyOrderedBroadcastAsUser(intent, null, null, null, 0, null, null); // $ hasAndroidIntentRedirection
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.security.AndroidIntentRedirectQuery
|
import semmle.code.java.security.AndroidIntentRedirectionQuery
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class HasAndroidIntentRedirectTest extends InlineExpectationsTest {
|
class HasAndroidIntentRedirectionTest extends InlineExpectationsTest {
|
||||||
HasAndroidIntentRedirectTest() { this = "HasAndroidIntentRedirectTest" }
|
HasAndroidIntentRedirectionTest() { this = "HasAndroidIntentRedirectionTest" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "hasAndroidIntentRedirect" }
|
override string getARelevantTag() { result = "hasAndroidIntentRedirection" }
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasAndroidIntentRedirect" and
|
tag = "hasAndroidIntentRedirection" and
|
||||||
exists(DataFlow::Node src, DataFlow::Node sink, IntentRedirectConfiguration conf |
|
exists(DataFlow::Node src, DataFlow::Node sink, IntentRedirectionConfiguration conf |
|
||||||
conf.hasFlow(src, sink)
|
conf.hasFlow(src, sink)
|
||||||
|
|
|
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme" >
|
android:theme="@style/AppTheme" >
|
||||||
<activity
|
<activity
|
||||||
android:name=".AndroidIntentRedirectTest"
|
android:name=".AndroidIntentRedirectionTest"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
Reference in New Issue
Block a user