Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d9c140d

Browse files
committed
Enhance the query to use sanitizer and null/empty array flow
1 parent 478771c commit d9c140d

5 files changed

Lines changed: 166 additions & 65 deletions

File tree

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
public void sendBroadcast1(Context context, String token, String refreshToken)
22
{
33
{
4-
// BAD: broadcast sensitive information without permission
4+
// BAD: broadcast sensitive information to all listeners
55
Intent intent = new Intent();
66
intent.setAction("com.example.custom_action");
77
intent.putExtra("token", token);
@@ -10,11 +10,21 @@ public void sendBroadcast1(Context context, String token, String refreshToken)
1010
}
1111

1212
{
13-
// GOOD: broadcast sensitive information with permission
13+
// GOOD: broadcast sensitive information only to those with permission
1414
Intent intent = new Intent();
1515
intent.setAction("com.example.custom_action");
1616
intent.putExtra("token", token);
1717
intent.putExtra("refreshToken", refreshToken);
1818
context.sendBroadcast(intent, "com.example.user_permission");
1919
}
20+
21+
{
22+
// GOOD: broadcast sensitive information to a specific application
23+
Intent intent = new Intent();
24+
intent.setAction("com.example.custom_action");
25+
intent.setClassName("com.example2", "com.example2.UserInfoHandler");
26+
intent.putExtra("token", token);
27+
intent.putExtra("refreshToken", refreshToken);
28+
context.sendBroadcast(intent);
29+
}
2030
}

java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.qhelp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
<qhelp>
55

66
<overview>
7-
<p>Broadcasted intents in an Android application are visible to all applications installed on the same mobile device, exposing all sensitive information they contain.</p>
8-
<p>Broadcasts are vulnerable to passive eavesdropping or active denial of service attacks when an intent is broadcasted without specifying any receiver permission or receiver application.</p>
7+
<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>
8+
<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>
99
</overview>
1010

1111
<recommendation>
12-
<p>Specify receiver permission or specify receiver application in broadcasted intents, or switch to <code>LocalBroadcastManager</code> or the latest <code>LiveData</code> library.</p>
12+
<p>Specify a receiver permission or application when broadcasting intents, or switch to <code>LocalBroadcastManager</code> or the latest <code>LiveData</code> library.</p>
1313
</recommendation>
1414

1515
<example>
16-
<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" is specified.</p>
16+
<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>
1717
<sample src="SensitiveBroadcast.java" />
1818
</example>
1919

java/ql/src/experimental/Security/CWE/CWE-927/SensitiveBroadcast.ql

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @name Use of Implicit Intent for Sensitive Communication
2+
* @name Broadcasting sensitive data to all Android applicationss
33
* @id java/sensitive-broadcast
44
* @description An Android application uses implicit intents to broadcast sensitive data to all applications without specifying any receiver permission.
55
* @kind path-problem
@@ -10,41 +10,48 @@
1010
import java
1111
import semmle.code.java.frameworks.android.Intent
1212
import semmle.code.java.dataflow.TaintTracking
13-
import DataFlow
14-
import PathGraph
1513

1614
/**
17-
* Gets a regular expression for matching names of variables that indicate the value being held contains sensitive information.
15+
* Gets a regular expression for matching common names of variables that indicate the value being held contains sensitive information.
1816
*/
19-
private string getSensitiveInfoRegex() {
17+
private string getCommonSensitiveInfoRegex() {
2018
result = "(?i).*challenge|pass(wd|word|code|phrase)(?!.*question).*" or
21-
result = "(?i).*(token|email|phone|username|userid|ticket).*"
19+
result = "(?i).*(token|username|userid|secret).*"
2220
}
2321

2422
/**
25-
* Method call to pass information to the `Intent` object either directly through intent extra or indirectly through intent extra bundle.
23+
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
2624
*/
27-
class PutExtraMethodAccess extends MethodAccess {
28-
PutExtraMethodAccess() {
25+
private string getAndroidSensitiveInfoRegex() { result = "(?i).*(email|phone|ticket).*" }
26+
27+
/**
28+
* Method call to pass information to the `Intent` object.
29+
*/
30+
class PutIntentExtraMethodAccess extends MethodAccess {
31+
PutIntentExtraMethodAccess() {
2932
getMethod().getName().regexpMatch("put\\w*Extra(s*)") and
30-
getMethod().getDeclaringType() instanceof TypeIntent and
31-
not exists(
32-
MethodAccess setPackageVa // Intent without specifying receiving package name of the 3rd party app
33-
|
34-
setPackageVa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
35-
setPackageVa.getQualifier().(VarAccess).getVariable().getAnAccess() = getQualifier()
36-
)
37-
or
33+
getMethod().getDeclaringType() instanceof TypeIntent
34+
}
35+
}
36+
37+
/**
38+
* Method call to pass information to the intent extra bundle object.
39+
*/
40+
class PutBundleExtraMethodAccess extends MethodAccess {
41+
PutBundleExtraMethodAccess() {
3842
getMethod().getName().regexpMatch("put\\w+") and
39-
getMethod().getDeclaringType().hasQualifiedName("android.os", "Bundle")
43+
getMethod().getDeclaringType().getASupertype*().hasQualifiedName("android.os", "BaseBundle")
4044
}
4145
}
4246

4347
/** Finds variables that hold sensitive information judging by their names. */
4448
class SensitiveInfoExpr extends Expr {
4549
SensitiveInfoExpr() {
4650
exists(Variable v | this = v.getAnAccess() |
47-
v.getName().toLowerCase().regexpMatch(getSensitiveInfoRegex())
51+
(
52+
v.getName().toLowerCase().regexpMatch(getCommonSensitiveInfoRegex()) or
53+
v.getName().toLowerCase().regexpMatch(getAndroidSensitiveInfoRegex())
54+
)
4855
)
4956
}
5057
}
@@ -59,6 +66,24 @@ class SendBroadcastMethodAccess extends MethodAccess {
5966
}
6067
}
6168

69+
private class NullArgFlowConfig extends DataFlow2::Configuration {
70+
NullArgFlowConfig() { this = "Flow configuration with a null argument" }
71+
72+
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof NullLiteral }
73+
74+
override predicate isSink(DataFlow::Node sink) { any() }
75+
}
76+
77+
private class EmptyArrayArgFlowConfig extends DataFlow2::Configuration {
78+
EmptyArrayArgFlowConfig() { this = "Flow configuration with an empty array argument" }
79+
80+
override predicate isSource(DataFlow::Node src) {
81+
src.asExpr().(ArrayCreationExpr).getFirstDimensionSize() = 0
82+
}
83+
84+
override predicate isSink(DataFlow::Node sink) { any() }
85+
}
86+
6287
/**
6388
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
6489
*/
@@ -68,47 +93,47 @@ predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
6893
(
6994
ma.getMethod().hasName("sendBroadcast") and
7095
(
71-
ma.getNumArgument() = 1 or // sendBroadcast(Intent intent)
72-
ma.getArgument(1) instanceof NullLiteral // sendBroadcast(Intent intent, String receiverPermission)
96+
ma.getNumArgument() = 1 // sendBroadcast(Intent intent)
97+
or
98+
// sendBroadcast(Intent intent, String receiverPermission)
99+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))))
73100
)
74101
or
75102
ma.getMethod().hasName("sendBroadcastAsUser") and
76103
(
77104
ma.getNumArgument() = 2 or // sendBroadcastAsUser(Intent intent, UserHandle user)
78-
ma.getArgument(2) instanceof NullLiteral // sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
105+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) // sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
79106
)
80107
or
81108
ma.getMethod().hasName("sendBroadcastWithMultiplePermissions") and
82-
(
83-
ma.getArgument(1).(ArrayCreationExpr).getFirstDimensionSize() = 0 // sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
84-
or
85-
exists(Variable v |
86-
v.getAnAccess() = ma.getArgument(1) and
87-
v.getAnAssignedValue().(ArrayCreationExpr).getFirstDimensionSize() = 0
88-
)
109+
exists(EmptyArrayArgFlowConfig config |
110+
config.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))) // sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
89111
)
90112
or
91113
//Method calls of `sendOrderedBroadcast` whose second argument is always `receiverPermission`
92114
ma.getMethod().hasName("sendOrderedBroadcast") and
93115
(
94-
ma.getArgument(1) instanceof NullLiteral and ma.getNumArgument() <=7
116+
// sendOrderedBroadcast(Intent intent, String receiverPermission) or sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
117+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
118+
ma.getNumArgument() <= 7
95119
or
96-
ma.getArgument(1) instanceof NullLiteral and
97-
ma.getArgument(2) instanceof NullLiteral and
120+
// sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
121+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
122+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) and
98123
ma.getNumArgument() = 8
99124
)
100125
or
101126
//Method call of `sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)`
102127
ma.getMethod().hasName("sendOrderedBroadcastAsUser") and
103-
ma.getArgument(2) instanceof NullLiteral
128+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2))))
104129
)
105130
)
106131
}
107132

108133
/**
109-
* Taint configuration tracking flow from variables containing sensitive information to broadcasted intents.
134+
* Taint configuration tracking flow from variables containing sensitive information to broadcast intents.
110135
*/
111-
class SensitiveBroadcastConfig extends DataFlow::Configuration {
136+
class SensitiveBroadcastConfig extends TaintTracking::Configuration {
112137
SensitiveBroadcastConfig() { this = "Sensitive Broadcast Configuration" }
113138

114139
override predicate isSource(DataFlow::Node source) {
@@ -118,11 +143,25 @@ class SensitiveBroadcastConfig extends DataFlow::Configuration {
118143
override predicate isSink(DataFlow::Node sink) { isSensitiveBroadcastSink(sink) }
119144

120145
/**
121-
* Holds if there is an additional flow step from `PutExtraMethodAccess` to a broadcasted intent.
146+
* Holds if there is an additional flow step from `PutIntentExtraMethodAccess` or `PutBundleExtraMethodAccess` to a broadcast intent.
147+
*/
148+
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
149+
exists(PutIntentExtraMethodAccess pia |
150+
node1.asExpr() = pia.getAnArgument() and node2.asExpr() = pia.getQualifier()
151+
)
152+
or
153+
exists(PutBundleExtraMethodAccess pba |
154+
node1.asExpr() = pba.getAnArgument() and node2.asExpr() = pba.getQualifier()
155+
)
156+
}
157+
158+
/**
159+
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
122160
*/
123-
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
124-
exists(PutExtraMethodAccess pa |
125-
node1.asExpr() = pa.getAnArgument() and node2.asExpr() = pa.getQualifier()
161+
override predicate isSanitizer(DataFlow::Node node) {
162+
exists(MethodAccess setReceiverMa |
163+
setReceiverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
164+
setReceiverMa.getQualifier().(VarAccess).getVariable().getAnAccess() = node.asExpr()
126165
)
127166
}
128167
}
Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
1-
edges
2-
| SensitiveBroadcast.java:11:34:11:38 | token : String | SensitiveBroadcast.java:13:31:13:36 | intent |
3-
| SensitiveBroadcast.java:12:41:12:52 | refreshToken : String | SensitiveBroadcast.java:13:31:13:36 | intent |
4-
| SensitiveBroadcast.java:23:33:23:40 | username : String | SensitiveBroadcast.java:25:31:25:36 | intent |
5-
| SensitiveBroadcast.java:24:32:24:39 | password : String | SensitiveBroadcast.java:25:31:25:36 | intent |
6-
| SensitiveBroadcast.java:36:40:36:47 | username : String | SensitiveBroadcast.java:39:31:39:36 | intent |
7-
| SensitiveBroadcast.java:37:39:37:46 | password : String | SensitiveBroadcast.java:39:31:39:36 | intent |
8-
nodes
9-
| SensitiveBroadcast.java:11:34:11:38 | token : String | semmle.label | token : String |
10-
| SensitiveBroadcast.java:12:41:12:52 | refreshToken : String | semmle.label | refreshToken : String |
11-
| SensitiveBroadcast.java:13:31:13:36 | intent | semmle.label | intent |
12-
| SensitiveBroadcast.java:23:33:23:40 | username : String | semmle.label | username : String |
13-
| SensitiveBroadcast.java:24:32:24:39 | password : String | semmle.label | password : String |
14-
| SensitiveBroadcast.java:25:31:25:36 | intent | semmle.label | intent |
15-
| SensitiveBroadcast.java:36:40:36:47 | username : String | semmle.label | username : String |
16-
| SensitiveBroadcast.java:37:39:37:46 | password : String | semmle.label | password : String |
17-
| SensitiveBroadcast.java:39:31:39:36 | intent | semmle.label | intent |
18-
#select
191
| SensitiveBroadcast.java:13:31:13:36 | intent | SensitiveBroadcast.java:11:34:11:38 | token : String | SensitiveBroadcast.java:13:31:13:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:11:34:11:38 | token | sensitive information |
202
| SensitiveBroadcast.java:13:31:13:36 | intent | SensitiveBroadcast.java:12:41:12:52 | refreshToken : String | SensitiveBroadcast.java:13:31:13:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:12:41:12:52 | refreshToken | sensitive information |
213
| SensitiveBroadcast.java:25:31:25:36 | intent | SensitiveBroadcast.java:23:33:23:40 | username : String | SensitiveBroadcast.java:25:31:25:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:23:33:23:40 | username | sensitive information |
224
| SensitiveBroadcast.java:25:31:25:36 | intent | SensitiveBroadcast.java:24:32:24:39 | password : String | SensitiveBroadcast.java:25:31:25:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:24:32:24:39 | password | sensitive information |
235
| SensitiveBroadcast.java:39:31:39:36 | intent | SensitiveBroadcast.java:36:40:36:47 | username : String | SensitiveBroadcast.java:39:31:39:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:36:40:36:47 | username | sensitive information |
246
| SensitiveBroadcast.java:39:31:39:36 | intent | SensitiveBroadcast.java:37:39:37:46 | password : String | SensitiveBroadcast.java:39:31:39:36 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:37:39:37:46 | password | sensitive information |
7+
| SensitiveBroadcast.java:89:54:89:59 | intent | SensitiveBroadcast.java:87:33:87:40 | username : String | SensitiveBroadcast.java:89:54:89:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:87:33:87:40 | username | sensitive information |
8+
| SensitiveBroadcast.java:89:54:89:59 | intent | SensitiveBroadcast.java:88:32:88:39 | password : String | SensitiveBroadcast.java:89:54:89:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:88:32:88:39 | password | sensitive information |
9+
| SensitiveBroadcast.java:102:54:102:59 | intent | SensitiveBroadcast.java:99:33:99:40 | username : String | SensitiveBroadcast.java:102:54:102:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:99:33:99:40 | username | sensitive information |
10+
| SensitiveBroadcast.java:102:54:102:59 | intent | SensitiveBroadcast.java:100:32:100:39 | password : String | SensitiveBroadcast.java:102:54:102:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:100:32:100:39 | password | sensitive information |
11+
| SensitiveBroadcast.java:116:54:116:59 | intent | SensitiveBroadcast.java:112:33:112:40 | username : String | SensitiveBroadcast.java:116:54:116:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:112:33:112:40 | username | sensitive information |
12+
| SensitiveBroadcast.java:116:54:116:59 | intent | SensitiveBroadcast.java:113:32:113:39 | password : String | SensitiveBroadcast.java:116:54:116:59 | intent | Sending $@ to broadcast. | SensitiveBroadcast.java:113:32:113:39 | password | sensitive information |

0 commit comments

Comments
 (0)