Merge pull request #6599 from joefarebrother/android-sensitive-communication

Java: Promote android sensitive broadcast query
This commit is contained in:
Joe Farebrother
2021-10-26 13:48:58 +01:00
committed by GitHub
13 changed files with 238 additions and 241 deletions

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The query "Leaking sensitive information through an implicit Intent" (`java/android/sensitive-communication`) has been promoted from experimental to the main query pack. Its results will now appear by default. The query was originally [submitted as an experimental query by @luchua-bc.](https://github.com/github/codeql/pull/4512)

View File

@@ -79,6 +79,7 @@ private module Frameworks {
private import internal.ContainerFlow private import internal.ContainerFlow
private import semmle.code.java.frameworks.android.Android private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.frameworks.android.Intent private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.android.XssSinks private import semmle.code.java.frameworks.android.XssSinks
private import semmle.code.java.frameworks.ApacheHttp private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.apache.Collections private import semmle.code.java.frameworks.apache.Collections
@@ -114,8 +115,6 @@ private module Frameworks {
private import semmle.code.java.security.OgnlInjection private import semmle.code.java.security.OgnlInjection
private import semmle.code.java.security.XPath private import semmle.code.java.security.XPath
private import semmle.code.java.security.XsltInjection private import semmle.code.java.security.XsltInjection
private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.Jdbc private import semmle.code.java.frameworks.Jdbc
private import semmle.code.java.frameworks.SpringJdbc private import semmle.code.java.frameworks.SpringJdbc
private import semmle.code.java.frameworks.MyBatis private import semmle.code.java.frameworks.MyBatis

View File

@@ -0,0 +1,179 @@
/** Provides definitions to reason about Android Sensitive Communication queries */
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.security.SensitiveActions
/**
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
*/
private string getAndroidSensitiveInfoRegex() { result = "(?i).*(email|phone|ticket).*" }
/** Finds variables that hold sensitive information judging by their names. */
private class SensitiveInfoExpr extends Expr {
SensitiveInfoExpr() {
exists(Variable v | this = v.getAnAccess() |
v.getName().regexpMatch([getCommonSensitiveInfoRegex(), getAndroidSensitiveInfoRegex()])
)
}
}
private predicate maybeNullArg(Expr ex) {
exists(DataFlow::Node src, DataFlow::Node sink, MethodAccess ma |
ex = ma.getAnArgument() and
sink.asExpr() = ex and
src.asExpr() instanceof NullLiteral
|
DataFlow::localFlow(src, sink)
)
}
private predicate maybeEmptyArrayArg(Expr ex) {
exists(DataFlow::Node src, DataFlow::Node sink, MethodAccess ma |
ex = ma.getAnArgument() and
sink.asExpr() = ex and
src.asExpr().(ArrayCreationExpr).getFirstDimensionSize() = 0
|
DataFlow::localFlow(src, sink)
)
}
/**
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
*/
private predicate isSensitiveBroadcastSink(DataFlow::Node sendBroadcastCallArg) {
exists(MethodAccess ma, string name | ma.getMethod().hasName(name) |
ma.getMethod().getDeclaringType().getASourceSupertype*() instanceof TypeContext and
sendBroadcastCallArg.asExpr() = ma.getAnArgument() and
(
name = "sendBroadcast" and
(
// sendBroadcast(Intent intent)
ma.getNumArgument() = 1
or
// sendBroadcast(Intent intent, String receiverPermission)
maybeNullArg(ma.getArgument(1))
)
or
name = "sendBroadcastAsUser" and
(
// sendBroadcastAsUser(Intent intent, UserHandle user)
ma.getNumArgument() = 2
or
// sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
maybeNullArg(ma.getArgument(2))
)
or
// sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
name = "sendBroadcastWithMultiplePermissions" and
maybeEmptyArrayArg(ma.getArgument(1))
or
// Method calls of `sendOrderedBroadcast` whose second argument is always `receiverPermission`
name = "sendOrderedBroadcast" and
(
// sendOrderedBroadcast(Intent intent, String receiverPermission)
// sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
maybeNullArg(ma.getArgument(1)) and
ma.getNumArgument() = [2, 7]
or
// sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
maybeNullArg(ma.getArgument(1)) and
maybeNullArg(ma.getArgument(2)) and
ma.getNumArgument() = 8
)
or
// sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
name = "sendOrderedBroadcastAsUser" and
maybeNullArg(ma.getArgument(2))
or
// sendStickyBroadcast(Intent intent)
// sendStickyBroadcast(Intent intent, Bundle options)
// sendStickyBroadcastAsUser(Intent intent, UserHandle user)
// sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
// sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
name =
[
"sendStickyBroadcast", "sendStickyBroadcastAsUser", "sendStickyOrderedBroadcast",
"sendStickyOrderedBroadcastAsUser"
]
)
)
}
/**
* Holds if `arg` is an argument in a use of a `startActivity` or `startService` method that sends an Intent to another application.
*/
private predicate isStartActivityOrServiceSink(DataFlow::Node arg) {
exists(MethodAccess ma, string name | ma.getMethod().hasName(name) |
arg.asExpr() = ma.getArgument(0) and
ma.getMethod().getDeclaringType().getASourceSupertype*() instanceof TypeContext and
// startActivity(Intent intent)
// startActivity(Intent intent, Bundle options)
// startActivities(Intent[] intents)
// startActivities(Intent[] intents, Bundle options)
// startService(Intent service)
// startForegroundService(Intent service)
// bindService (Intent service, int flags, Executor executor, ServiceConnection conn)
// bindService (Intent service, Executor executor, ServiceConnection conn)
name =
["startActivity", "startActivities", "startService", "startForegroundService", "bindService"]
)
}
private predicate isCleanIntent(Expr intent) {
intent.getType() instanceof TypeIntent and
(
exists(MethodAccess setRecieverMa |
setRecieverMa.getQualifier() = intent and
setRecieverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"])
)
or
// Handle the cases where the PackageContext and Class are set at construction time
// Intent(Context packageContext, Class<?> cls)
// Intent(String action, Uri uri, Context packageContext, Class<?> cls)
exists(ConstructorCall cc | cc = intent |
cc.getConstructedType() instanceof TypeIntent and
cc.getNumArgument() > 1 and
(
cc.getArgument(0).getType() instanceof TypeContext and
not maybeNullArg(cc.getArgument(1))
or
cc.getArgument(2).getType() instanceof TypeContext and
not maybeNullArg(cc.getArgument(3))
)
)
)
}
/**
* Taint configuration tracking flow from variables containing sensitive information to broadcast Intents.
*/
class SensitiveCommunicationConfig extends TaintTracking::Configuration {
SensitiveCommunicationConfig() { this = "Sensitive Communication Configuration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SensitiveInfoExpr
}
override predicate isSink(DataFlow::Node sink) {
isSensitiveBroadcastSink(sink)
or
isStartActivityOrServiceSink(sink)
}
/**
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
*/
override predicate isSanitizer(DataFlow::Node node) {
exists(DataFlow::Node intent | isCleanIntent(intent.asExpr()) |
DataFlow::localFlow(intent, node)
)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
super.allowImplicitRead(node, c)
or
this.isSink(node)
}
}

View File

@@ -2,30 +2,24 @@
<qhelp> <qhelp>
<overview> <overview>
<p>Broadcast intents in an Android application are visible to all applications installed on the same mobile device, exposing all sensitive information they contain.</p> <p>When an implicit Intent is used with a method such as <code>startActivity</code>, <code>startService</code>, or <code>sendBroadcast</code>, it may be read by other applications on the device.</p>
<p>Broadcasts are vulnerable to passive eavesdropping or active denial of service attacks when an intent is broadcast without specifying any receiver permission or receiver application.</p> <p>This means that sensitive data in these Intents may be leaked.</p>
</overview> </overview>
<recommendation> <recommendation>
<p> <p>
Specify a receiver permission or application when broadcasting intents, or switch to For <code>sendBroadcast</code> methods, a receiver permission may be specified so that only applications with a certain permission may receive the Intent;
<code>LocalBroadcastManager</code> or a <code>LocalBroadcastManager</code> may be used.
or the latest Otherwise, ensure that Intents containing sensitive data have an explicit receiver class set.
<code>LiveData</code>
library.
</p> </p>
</recommendation> </recommendation>
<example> <example>
<p>The following example shows two ways of broadcasting intents. In the 'BAD' case, no "receiver permission" is specified. In the 'GOOD' case, "receiver permission" or "receiver application" is specified.</p> <p>The following example shows two ways of broadcasting Intents. In the 'BAD' case, no "receiver permission" is specified. In the 'GOOD' case, "receiver permission" or "receiver application" is specified.</p>
<sample src="SensitiveBroadcast.java" /> <sample src="SensitiveCommunication.java" />
</example> </example>
<references> <references>
<li>
CWE:
<a href="https://cwe.mitre.org/data/definitions/927.html">CWE-927: Use of Implicit Intent for Sensitive Communication</a>
</li>
<li> <li>
Android Developers: Android Developers:
<a href="https://developer.android.com/guide/components/broadcasts">Security considerations and best practices for sending and receiving broadcasts</a> <a href="https://developer.android.com/guide/components/broadcasts">Security considerations and best practices for sending and receiving broadcasts</a>
@@ -46,5 +40,9 @@
Android Developers: Android Developers:
<a href="https://developer.android.com/topic/libraries/architecture/livedata">Android LiveData Overview</a> <a href="https://developer.android.com/topic/libraries/architecture/livedata">Android LiveData Overview</a>
</li> </li>
<li>
Oversecured:
<a href="https://blog.oversecured.com/Interception-of-Android-implicit-intents/">Interception of Android implicit intents</a>
</li>
</references> </references>
</qhelp> </qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name Leaking sensitive information through an implicit Intent
* @description An Android application uses implicit Intents containing sensitive data
* in a way that exposes it to arbitrary applications on the device.
* @kind path-problem
* @problem.severity warning
* @security-severity 8.2
* @precision medium
* @id java/android/sensitive-communication
* @tags security
* external/cwe/cwe-927
*/
import java
import semmle.code.java.security.AndroidSensitiveCommunicationQuery
import DataFlow::PathGraph
from SensitiveCommunicationConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This call may leak sensitive information from $@.",
source.getNode(), "here"

View File

@@ -1,175 +0,0 @@
/**
* @name Broadcasting sensitive data to all Android applications
* @description An Android application uses implicit intents to broadcast
* sensitive data to all applications without specifying any
* receiver permission.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @id java/sensitive-broadcast
* @tags security
* external/cwe/cwe-927
*/
import java
import semmle.code.java.dataflow.DataFlow3
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.security.SensitiveActions
import DataFlow::PathGraph
/**
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
*/
private string getAndroidSensitiveInfoRegex() { result = "(?i).*(email|phone|ticket).*" }
/**
* Method call to pass information to the `Intent` object.
*/
class PutIntentExtraMethodAccess extends MethodAccess {
PutIntentExtraMethodAccess() {
(
getMethod().getName().matches("put%Extra") or
getMethod().hasName("putExtras")
) and
getMethod().getDeclaringType() instanceof TypeIntent
}
}
/**
* Method call to pass information to the intent extra bundle object.
*/
class PutBundleExtraMethodAccess extends MethodAccess {
PutBundleExtraMethodAccess() {
getMethod().getName().regexpMatch("put\\w+") and
getMethod().getDeclaringType().getASupertype*().hasQualifiedName("android.os", "BaseBundle")
}
}
/** Finds variables that hold sensitive information judging by their names. */
class SensitiveInfoExpr extends Expr {
SensitiveInfoExpr() {
exists(Variable v | this = v.getAnAccess() |
v.getName().regexpMatch([getCommonSensitiveInfoRegex(), getAndroidSensitiveInfoRegex()])
)
}
}
/**
* A method access of the `Context.sendBroadcast` family.
*/
class SendBroadcastMethodAccess extends MethodAccess {
SendBroadcastMethodAccess() {
this.getMethod().getDeclaringType() instanceof TypeContext and
this.getMethod().getName().matches("send%Broadcast%")
}
}
private class NullArgFlowConfig extends DataFlow2::Configuration {
NullArgFlowConfig() { this = "Flow configuration with a null argument" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof NullLiteral }
override predicate isSink(DataFlow::Node sink) {
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
}
}
private class EmptyArrayArgFlowConfig extends DataFlow3::Configuration {
EmptyArrayArgFlowConfig() { this = "Flow configuration with an empty array argument" }
override predicate isSource(DataFlow::Node src) {
src.asExpr().(ArrayCreationExpr).getFirstDimensionSize() = 0
}
override predicate isSink(DataFlow::Node sink) {
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
}
}
/**
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
*/
predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
exists(SendBroadcastMethodAccess ma |
sink.asExpr() = ma.getAnArgument() and
(
ma.getMethod().hasName("sendBroadcast") and
(
ma.getNumArgument() = 1 // sendBroadcast(Intent intent)
or
// sendBroadcast(Intent intent, String receiverPermission)
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))))
)
or
ma.getMethod().hasName("sendBroadcastAsUser") and
(
ma.getNumArgument() = 2 or // sendBroadcastAsUser(Intent intent, UserHandle user)
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) // sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
)
or
ma.getMethod().hasName("sendBroadcastWithMultiplePermissions") and
exists(EmptyArrayArgFlowConfig config |
config.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))) // sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
)
or
// Method calls of `sendOrderedBroadcast` whose second argument is always `receiverPermission`
ma.getMethod().hasName("sendOrderedBroadcast") and
(
// sendOrderedBroadcast(Intent intent, String receiverPermission) or sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
ma.getNumArgument() <= 7
or
// sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) and
ma.getNumArgument() = 8
)
or
// Method call of `sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)`
ma.getMethod().hasName("sendOrderedBroadcastAsUser") and
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2))))
)
)
}
/**
* Taint configuration tracking flow from variables containing sensitive information to broadcast intents.
*/
class SensitiveBroadcastConfig extends TaintTracking::Configuration {
SensitiveBroadcastConfig() { this = "Sensitive Broadcast Configuration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SensitiveInfoExpr
}
override predicate isSink(DataFlow::Node sink) { isSensitiveBroadcastSink(sink) }
/**
* Holds if there is an additional flow step from `PutIntentExtraMethodAccess` or `PutBundleExtraMethodAccess` that taints the `Intent` or its extras `Bundle`.
*/
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(PutIntentExtraMethodAccess pia |
node1.asExpr() = pia.getAnArgument() and node2.asExpr() = pia.getQualifier()
)
or
exists(PutBundleExtraMethodAccess pba |
node1.asExpr() = pba.getAnArgument() and node2.asExpr() = pba.getQualifier()
)
}
/**
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
*/
override predicate isSanitizer(DataFlow::Node node) {
exists(MethodAccess setReceiverMa |
setReceiverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
setReceiverMa.getQualifier().(VarAccess).getVariable().getAnAccess() = node.asExpr()
)
}
}
from SensitiveBroadcastConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Sending $@ to broadcast.", source.getNode(),
"sensitive information"

View File

@@ -1,37 +0,0 @@
edges
| SensitiveBroadcast.java:12:34:12:38 | token : String | SensitiveBroadcast.java:14:31:14:36 | intent |
| SensitiveBroadcast.java:13:41:13:52 | refreshToken : String | SensitiveBroadcast.java:14:31:14:36 | intent |
| SensitiveBroadcast.java:25:32:25:39 | password : String | SensitiveBroadcast.java:26:31:26:36 | intent |
| SensitiveBroadcast.java:36:35:36:39 | email : String | SensitiveBroadcast.java:38:31:38:36 | intent |
| SensitiveBroadcast.java:50:9:50:16 | userinfo [post update] [<element>] : String | SensitiveBroadcast.java:52:31:52:36 | intent |
| SensitiveBroadcast.java:50:22:50:29 | password : String | SensitiveBroadcast.java:50:9:50:16 | userinfo [post update] [<element>] : String |
| SensitiveBroadcast.java:97:35:97:40 | ticket : String | SensitiveBroadcast.java:98:54:98:59 | intent |
| SensitiveBroadcast.java:109:32:109:39 | passcode : String | SensitiveBroadcast.java:111:54:111:59 | intent |
| SensitiveBroadcast.java:136:33:136:38 | passwd : String | SensitiveBroadcast.java:140:54:140:59 | intent |
nodes
| SensitiveBroadcast.java:12:34:12:38 | token : String | semmle.label | token : String |
| SensitiveBroadcast.java:13:41:13:52 | refreshToken : String | semmle.label | refreshToken : String |
| SensitiveBroadcast.java:14:31:14:36 | intent | semmle.label | intent |
| SensitiveBroadcast.java:25:32:25:39 | password : String | semmle.label | password : String |
| SensitiveBroadcast.java:26:31:26:36 | intent | semmle.label | intent |
| SensitiveBroadcast.java:36:35:36:39 | email : String | semmle.label | email : String |
| SensitiveBroadcast.java:38:31:38:36 | intent | semmle.label | intent |
| SensitiveBroadcast.java:50:9:50:16 | userinfo [post update] [<element>] : String | semmle.label | userinfo [post update] [<element>] : String |
| SensitiveBroadcast.java:50:22:50:29 | password : String | semmle.label | password : String |
| SensitiveBroadcast.java:52:31:52:36 | intent | semmle.label | intent |
| SensitiveBroadcast.java:97:35:97:40 | ticket : String | semmle.label | ticket : String |
| SensitiveBroadcast.java:98:54:98:59 | intent | semmle.label | intent |
| SensitiveBroadcast.java:109:32:109:39 | passcode : String | semmle.label | passcode : String |
| SensitiveBroadcast.java:111:54:111:59 | intent | semmle.label | intent |
| SensitiveBroadcast.java:136:33:136:38 | passwd : String | semmle.label | passwd : String |
| SensitiveBroadcast.java:140:54:140:59 | intent | semmle.label | intent |
subpaths
#select
| SensitiveBroadcast.java:14:31:14:36 | intent | SensitiveBroadcast.java:12:34:12:38 | token : String | SensitiveBroadcast.java:14:31:14:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:12:34:12:38 | token | sensitive information |
| SensitiveBroadcast.java:14:31:14:36 | intent | SensitiveBroadcast.java:13:41:13:52 | refreshToken : String | SensitiveBroadcast.java:14:31:14:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:13:41:13:52 | refreshToken | sensitive information |
| SensitiveBroadcast.java:26:31:26:36 | intent | SensitiveBroadcast.java:25:32:25:39 | password : String | SensitiveBroadcast.java:26:31:26:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:25:32:25:39 | password | sensitive information |
| SensitiveBroadcast.java:38:31:38:36 | intent | SensitiveBroadcast.java:36:35:36:39 | email : String | SensitiveBroadcast.java:38:31:38:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:36:35:36:39 | email | sensitive information |
| SensitiveBroadcast.java:52:31:52:36 | intent | SensitiveBroadcast.java:50:22:50:29 | password : String | SensitiveBroadcast.java:52:31:52:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:50:22:50:29 | password | sensitive information |
| SensitiveBroadcast.java:98:54:98:59 | intent | SensitiveBroadcast.java:97:35:97:40 | ticket : String | SensitiveBroadcast.java:98:54:98:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:97:35:97:40 | ticket | sensitive information |
| SensitiveBroadcast.java:111:54:111:59 | intent | SensitiveBroadcast.java:109:32:109:39 | passcode : String | SensitiveBroadcast.java:111:54:111:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:109:32:109:39 | passcode | sensitive information |
| SensitiveBroadcast.java:140:54:140:59 | intent | SensitiveBroadcast.java:136:33:136:38 | passwd : String | SensitiveBroadcast.java:140:54:140:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:136:33:136:38 | passwd | sensitive information |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql

View File

@@ -11,7 +11,7 @@ class SensitiveBroadcast {
intent.setAction("com.example.custom_action"); intent.setAction("com.example.custom_action");
intent.putExtra("token", token); intent.putExtra("token", token);
intent.putExtra("refreshToken", refreshToken); intent.putExtra("refreshToken", refreshToken);
context.sendBroadcast(intent); context.sendBroadcast(intent); // $ hasTaintFlow
} }
// BAD - Tests broadcast of sensitive user information with intent extra. // BAD - Tests broadcast of sensitive user information with intent extra.
@@ -23,7 +23,7 @@ class SensitiveBroadcast {
intent.setAction("com.example.custom_action"); intent.setAction("com.example.custom_action");
intent.putExtra("name", userName); intent.putExtra("name", userName);
intent.putExtra("pwd", password); intent.putExtra("pwd", password);
context.sendBroadcast(intent); context.sendBroadcast(intent); // $ hasTaintFlow
} }
// BAD - Tests broadcast of email information with extra bundle. // BAD - Tests broadcast of email information with extra bundle.
@@ -35,7 +35,7 @@ class SensitiveBroadcast {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString("email", email); bundle.putString("email", email);
intent.putExtras(bundle); intent.putExtras(bundle);
context.sendBroadcast(intent); context.sendBroadcast(intent); // $ hasTaintFlow
} }
// BAD - Tests broadcast of sensitive user information with null permission. // BAD - Tests broadcast of sensitive user information with null permission.
@@ -49,7 +49,7 @@ class SensitiveBroadcast {
userinfo.add(username); userinfo.add(username);
userinfo.add(password); userinfo.add(password);
intent.putStringArrayListExtra("userinfo", userinfo); intent.putStringArrayListExtra("userinfo", userinfo);
context.sendBroadcast(intent, null); context.sendBroadcast(intent, null); // $ hasTaintFlow
} }
// GOOD - Tests broadcast of sensitive user information with permission using string literal. // GOOD - Tests broadcast of sensitive user information with permission using string literal.
@@ -95,7 +95,7 @@ class SensitiveBroadcast {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction("com.example.custom_action"); intent.setAction("com.example.custom_action");
intent.putExtra("ticket", ticket); intent.putExtra("ticket", ticket);
context.sendBroadcastWithMultiplePermissions(intent, new String[]{}); context.sendBroadcastWithMultiplePermissions(intent, new String[]{}); // $ hasTaintFlow
} }
// BAD - Tests broadcast of sensitive user information with multiple permissions using empty array initialization through a variable. // BAD - Tests broadcast of sensitive user information with multiple permissions using empty array initialization through a variable.
@@ -108,7 +108,7 @@ class SensitiveBroadcast {
intent.putExtra("name", username); intent.putExtra("name", username);
intent.putExtra("pwd", passcode); intent.putExtra("pwd", passcode);
String[] perms = new String[0]; String[] perms = new String[0];
context.sendBroadcastWithMultiplePermissions(intent, perms); context.sendBroadcastWithMultiplePermissions(intent, perms); // $ hasTaintFlow
} }
// GOOD - Tests broadcast of sensitive user information with multiple permissions. // GOOD - Tests broadcast of sensitive user information with multiple permissions.
@@ -137,12 +137,11 @@ class SensitiveBroadcast {
intent.putExtras(bundle); intent.putExtras(bundle);
String[] perms = new String[0]; String[] perms = new String[0];
String[] perms2 = perms; String[] perms2 = perms;
context.sendBroadcastWithMultiplePermissions(intent, perms2); context.sendBroadcastWithMultiplePermissions(intent, perms2); // $ hasTaintFlow
} }
/** /**
* BAD - Tests broadcast of sensitive user information with multiple permissions using empty array initialization through two variables and `intent.getExtras().putString()`. * BAD - Tests broadcast of sensitive user information with multiple permissions using empty array initialization through two variables and `intent.getExtras().putString()`.
* Note this case of `getExtras().putString(...)` is not yet detected thus is beyond what the query is capable of.
*/ */
public void sendBroadcast12(Context context) { public void sendBroadcast12(Context context) {
String username = "test123"; String username = "test123";
@@ -156,7 +155,7 @@ class SensitiveBroadcast {
intent.getExtras().putString("pwd", password); intent.getExtras().putString("pwd", password);
String[] perms = new String[0]; String[] perms = new String[0];
String[] perms2 = perms; String[] perms2 = perms;
context.sendBroadcastWithMultiplePermissions(intent, perms2); context.sendBroadcastWithMultiplePermissions(intent, perms2); // $ hasTaintFlow
} }
// GOOD - Tests broadcast of sensitive user information with ordered broadcast. // GOOD - Tests broadcast of sensitive user information with ordered broadcast.

View File

@@ -0,0 +1,12 @@
import java
import semmle.code.java.security.AndroidSensitiveCommunicationQuery
import TestUtilities.InlineExpectationsTest
import TestUtilities.InlineFlowTest
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() {
result = any(SensitiveCommunicationConfig c)
}
override DataFlow::Configuration getValueFlowConfig() { none() }
}

View File

@@ -1 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0 // semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/google-android-9.0.0