-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
ArbitraryApkInstallationQuery.qll
117 lines (101 loc) · 3.75 KB
/
ArbitraryApkInstallationQuery.qll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/** Provides dataflow configurations to reason about installation of arbitrary Android APKs. */
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.security.ArbitraryApkInstallation
/**
* A dataflow configuration for flow from an external source of an APK to the
* `setData[AndType][AndNormalize]` method of an intent.
*/
module ApkInstallationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
predicate isSink(DataFlow::Node node) {
exists(MethodCall ma |
ma.getMethod() instanceof SetDataMethod and
ma.getArgument(0) = node.asExpr() and
(
PackageArchiveMimeTypeFlow::flowToExpr(ma.getQualifier())
or
InstallPackageActionFlow::flowToExpr(ma.getQualifier())
)
)
}
}
module ApkInstallationFlow = DataFlow::Global<ApkInstallationConfig>;
private newtype ActionState =
ActionUnset() or
HasInstallPackageAction()
/**
* A dataflow configuration tracking the flow from the `android.content.Intent.ACTION_INSTALL_PACKAGE`
* constant to either the constructor of an intent or the `setAction` method of an intent.
*
* This is used to track if an intent is used to install an APK.
*/
private module InstallPackageActionConfig implements DataFlow::StateConfigSig {
class FlowState = ActionState;
predicate isSource(DataFlow::Node source, FlowState state) {
source.asExpr() instanceof InstallPackageAction and state instanceof ActionUnset
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
state1 instanceof ActionUnset and
state2 instanceof HasInstallPackageAction and
(
exists(ConstructorCall cc |
cc.getConstructedType() instanceof TypeIntent and
node1.asExpr() = cc.getArgument(0) and
node1.asExpr().getType() instanceof TypeString and
node2.asExpr() = cc
)
or
exists(MethodCall ma |
ma.getMethod() instanceof SetActionMethod and
node1.asExpr() = ma.getArgument(0) and
node2.asExpr() = ma.getQualifier()
)
)
}
predicate isSink(DataFlow::Node node, FlowState state) {
state instanceof HasInstallPackageAction and node.asExpr().getType() instanceof TypeIntent
}
}
private module InstallPackageActionFlow =
TaintTracking::GlobalWithState<InstallPackageActionConfig>;
private newtype MimeTypeState =
MimeTypeUnset() or
HasPackageArchiveMimeType()
/**
* A dataflow configuration tracking the flow of the Android APK MIME type to
* the `setType` or `setTypeAndNormalize` method of an intent, followed by a call
* to `setData[AndType][AndNormalize]`.
*/
private module PackageArchiveMimeTypeConfig implements DataFlow::StateConfigSig {
class FlowState = MimeTypeState;
predicate isSource(DataFlow::Node node, FlowState state) {
node.asExpr() instanceof PackageArchiveMimeTypeLiteral and
state instanceof MimeTypeUnset
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
state1 instanceof MimeTypeUnset and
state2 instanceof HasPackageArchiveMimeType and
exists(MethodCall ma |
ma.getQualifier() = node2.asExpr() and
(
ma.getMethod() instanceof SetTypeMethod and
ma.getArgument(0) = node1.asExpr()
or
ma.getMethod() instanceof SetDataAndTypeMethod and
ma.getArgument(1) = node1.asExpr()
)
)
}
predicate isSink(DataFlow::Node node, FlowState state) {
state instanceof HasPackageArchiveMimeType and
node instanceof SetDataSink
}
}
private module PackageArchiveMimeTypeFlow =
TaintTracking::GlobalWithState<PackageArchiveMimeTypeConfig>;