Repository navigation
Expand file tree
/
Copy pathFlowSources.qll
More file actions
412 lines (344 loc) · 13 KB
/
Copy pathFlowSources.qll
File metadata and controls
412 lines (344 loc) · 13 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/**
* Provides classes representing various flow sources for taint tracking.
*/
overlay[local?]
module;
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.DefUse
import semmle.code.java.frameworks.Jdbc
import semmle.code.java.frameworks.Networking
import semmle.code.java.frameworks.Properties
import semmle.code.java.frameworks.Rmi
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.ApacheHttp
import semmle.code.java.frameworks.android.XmlParsing
import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.WebSocket
import semmle.code.java.frameworks.android.Android
import semmle.code.java.frameworks.android.ExternalStorage
import semmle.code.java.frameworks.android.OnActivityResultSource
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.play.Play
import semmle.code.java.frameworks.spring.SpringWeb
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringWebClient
import semmle.code.java.frameworks.Guice
import semmle.code.java.frameworks.struts.StrutsActions
import semmle.code.java.frameworks.Thrift
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
import semmle.code.java.frameworks.micronaut.MicronautController
import semmle.code.java.frameworks.micronaut.MicronautWebSocket
private import semmle.code.java.dataflow.ExternalFlow
private import codeql.threatmodels.ThreatModels
/**
* A data flow source.
*/
abstract class SourceNode extends DataFlow::Node {
/**
* Gets a string that represents the source kind with respect to threat modeling.
*/
abstract string getThreatModel();
}
/**
* A data flow source that is enabled in the current threat model configuration.
*/
class ActiveThreatModelSource extends DataFlow::Node {
ActiveThreatModelSource() {
exists(string kind |
// Specific threat model.
currentThreatModel(kind) and
(this.(SourceNode).getThreatModel() = kind or sourceNode(this, kind))
)
}
}
/** A data flow source of remote user input. */
abstract class RemoteFlowSource extends SourceNode {
/** Gets a string that describes the type of this remote flow source. */
abstract string getSourceType();
override string getThreatModel() { result = "remote" }
}
/**
* A module for importing frameworks that define flow sources.
*/
private module FlowSources {
private import semmle.code.java.frameworks.hudson.Hudson
private import semmle.code.java.frameworks.stapler.Stapler
}
private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
override string getSourceType() { result = "external" }
}
private class RmiMethodParameterSource extends RemoteFlowSource {
RmiMethodParameterSource() {
exists(RemoteCallableMethod method |
method.getAParameter() = this.asParameter() and
(
this.getType() instanceof PrimitiveType or
this.getType() instanceof TypeString
)
)
}
override string getSourceType() { result = "RMI method parameter" }
}
private class JaxWsMethodParameterSource extends RemoteFlowSource {
JaxWsMethodParameterSource() {
exists(JaxWsEndpoint endpoint |
endpoint.getARemoteMethod().getAParameter() = this.asParameter()
)
}
override string getSourceType() { result = "Jax WS method parameter" }
}
private class JaxRsMethodParameterSource extends RemoteFlowSource {
JaxRsMethodParameterSource() {
exists(JaxRsResourceClass service |
service.getAnInjectableCallable().getAParameter() = this.asParameter() or
service.getAnInjectableField().getAnAccess() = this.asExpr()
)
}
override string getSourceType() { result = "Jax Rs method parameter" }
}
private predicate variableStep(Expr tracked, VarAccess sink) {
exists(VariableAssign def |
def.getSource() = tracked and
defUsePair(def, sink)
)
}
private class MessageBodyReaderParameterSource extends RemoteFlowSource {
MessageBodyReaderParameterSource() {
exists(MessageBodyReaderRead m |
m.getParameter(4) = this.asParameter() or
m.getParameter(5) = this.asParameter()
)
}
override string getSourceType() { result = "MessageBodyReader parameter" }
}
private class PlayParameterSource extends RemoteFlowSource {
PlayParameterSource() { this.asParameter() instanceof PlayActionMethodQueryParameter }
override string getSourceType() { result = "Play Query Parameters" }
}
private class SpringServletInputParameterSource extends RemoteFlowSource {
SpringServletInputParameterSource() {
this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput())
}
override string getSourceType() { result = "Spring servlet input parameter" }
}
private class GuiceRequestParameterSource extends RemoteFlowSource {
GuiceRequestParameterSource() {
exists(GuiceRequestParametersAnnotation a |
a = this.asParameter().getAnAnnotation() or
a = this.asExpr().(FieldRead).getField().getAnAnnotation()
)
}
override string getSourceType() { result = "Guice request parameter" }
}
private class Struts2ActionSupportClassFieldSource extends RemoteFlowSource {
Struts2ActionSupportClassFieldSource() {
this.(DataFlow::FieldValueNode).getField() =
any(Struts2ActionSupportClass c).getASetterMethod().getField()
}
override string getSourceType() { result = "Struts2 ActionSupport field" }
}
private class ThriftIfaceParameterSource extends RemoteFlowSource {
ThriftIfaceParameterSource() {
exists(ThriftIface i | i.getAnImplementingMethod().getAParameter() = this.asParameter())
}
override string getSourceType() { result = "Thrift Iface parameter" }
}
private class AndroidExternalStorageSource extends RemoteFlowSource {
AndroidExternalStorageSource() { androidExternalStorageSource(this) }
override string getSourceType() { result = "Android external storage" }
}
private class MicronautHttpInputParameterSource extends RemoteFlowSource {
MicronautHttpInputParameterSource() {
this.asParameter() = any(MicronautRequestMappingParameter mrmp | mrmp.isTaintedInput())
}
override string getSourceType() { result = "Micronaut HTTP input parameter" }
}
private class MicronautWebSocketParameterSource extends RemoteFlowSource {
MicronautWebSocketParameterSource() { this.asParameter() instanceof MicronautWebSocketParameter }
override string getSourceType() { result = "Micronaut WebSocket parameter" }
}
private class MicronautErrorHandlerSource extends RemoteFlowSource {
MicronautErrorHandlerSource() {
this.asParameter() = any(MicronautErrorHandler h).getARemoteParameter()
}
override string getSourceType() { result = "Micronaut error handler parameter" }
}
/** Class for `tainted` user input. */
abstract class UserInput extends SourceNode { }
/**
* Input that may be controlled by a remote user.
*/
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource {
override string getThreatModel() { result = RemoteFlowSource.super.getThreatModel() }
}
/** A node with input that may be controlled by a local user. */
abstract class LocalUserInput extends UserInput {
override string getThreatModel() { result = "local" }
}
/**
* A node with input from the local environment, such as
* environment variables.
*/
private class EnvironmentInput extends LocalUserInput {
EnvironmentInput() { sourceNode(this, "environment") }
override string getThreatModel() { result = "environment" }
}
/**
* A node with input from the command line, such as standard in
* and main method parameters.
*/
private class CliInput extends LocalUserInput {
CliInput() {
// Parameters to a main method.
exists(MainMethod main | this.asParameter() = main.getParameter(0))
or
// Args4j arguments.
exists(Field f | this.asExpr() = f.getAnAccess() |
f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument"
)
}
override string getThreatModel() { result = "commandargs" }
}
/**
* A node with input from stdin.
*/
private class StdinInput extends LocalUserInput {
StdinInput() {
// Access to `System.in`.
exists(Field f | this.asExpr() = f.getAnAccess() | f instanceof SystemIn)
}
override string getThreatModel() { result = "stdin" }
}
/**
* A node with input from the local environment, such as files.
*/
private class FileInput extends LocalUserInput {
FileInput() {
// Access to files.
sourceNode(this, "file")
}
override string getThreatModel() { result = "file" }
}
/**
* A node with input from a database.
*/
private class DbInput extends LocalUserInput {
DbInput() { sourceNode(this, "database") }
override string getThreatModel() { result = "database" }
}
/** A method that reads from the environment, such as `System.getProperty` or `System.getenv`. */
class EnvReadMethod extends Method {
EnvReadMethod() {
this instanceof MethodSystemGetenv or
this instanceof PropertiesGetPropertyMethod or
this instanceof PropertiesGetMethod or
this instanceof MethodSystemGetProperty
}
}
/** The type `java.net.InetAddress`. */
class TypeInetAddr extends RefType {
TypeInetAddr() { this.hasQualifiedName("java.net", "InetAddress") }
}
/** A reverse DNS method. */
class ReverseDnsMethod extends Method {
ReverseDnsMethod() {
this.getDeclaringType() instanceof TypeInetAddr and
(
this.getName() = "getHostName" or
this.getName() = "getCanonicalHostName"
)
}
}
/** Android `Intent` that may have come from a hostile application. */
class AndroidIntentInput extends DataFlow::Node {
Type receiverType;
AndroidIntentInput() {
exists(MethodCall ma, AndroidGetIntentMethod m |
ma.getMethod().overrides*(m) and
this.asExpr() = ma and
receiverType = ma.getReceiverType()
)
or
exists(Method m, AndroidReceiveIntentMethod rI |
m.overrides*(rI) and
this.asParameter() = m.getParameter(1) and
receiverType = m.getDeclaringType()
)
or
exists(Method m, AndroidServiceIntentMethod sI |
m.overrides*(sI) and
this.asParameter() = m.getParameter(0) and
receiverType = m.getDeclaringType()
)
}
}
/** Exported Android `Intent` that may have come from a hostile application. */
class ExportedAndroidIntentInput extends RemoteFlowSource, AndroidIntentInput {
ExportedAndroidIntentInput() { receiverType.(ExportableAndroidComponent).isExported() }
override string getSourceType() { result = "Exported Android intent source" }
}
/** A parameter of an entry-point method declared in a `ContentProvider` class. */
class AndroidContentProviderInput extends DataFlow::Node {
AndroidContentProvider declaringType;
AndroidContentProviderInput() {
sourceNode(this, "contentprovider") and
this.getEnclosingCallable().getDeclaringType() = declaringType
}
}
/** A parameter of an entry-point method declared in an exported `ContentProvider` class. */
class ExportedAndroidContentProviderInput extends RemoteFlowSource, AndroidContentProviderInput {
ExportedAndroidContentProviderInput() { declaringType.isExported() }
override string getSourceType() { result = "Exported Android content provider source" }
}
/**
* The data Intent parameter in the `onActivityResult` method in an Activity or Fragment that
* calls `startActivityForResult` with an implicit Intent.
*/
class OnActivityResultIntentSource extends OnActivityResultIncomingIntent, RemoteFlowSource {
cached
OnActivityResultIntentSource() { this.isRemoteSource() }
override string getSourceType() { result = "Android onActivityResult incoming Intent" }
}
/**
* A parameter of a method annotated with the `android.webkit.JavascriptInterface` annotation.
*/
class AndroidJavascriptInterfaceMethodParameter extends RemoteFlowSource {
AndroidJavascriptInterfaceMethodParameter() {
exists(JavascriptInterfaceMethod m | this.asParameter() = m.getAParameter())
}
override string getSourceType() {
result = "Parameter of method with JavascriptInterface annotation"
}
}
/** A node with input that comes from a reverse DNS lookup. */
abstract class ReverseDnsUserInput extends UserInput {
override string getThreatModel() { result = "reverse-dns" }
}
private class ReverseDnsSource extends ReverseDnsUserInput {
ReverseDnsSource() {
// Try not to trigger on `localhost`.
exists(MethodCall m | m = this.asExpr() |
m.getMethod() instanceof ReverseDnsMethod and
not exists(MethodCall l |
(variableStep(l, m.getQualifier()) or l = m.getQualifier()) and
(l.getMethod().getName() = "getLocalHost" or l.getMethod().getName() = "getLoopbackAddress")
)
)
}
}
/**
* A data flow source node for an API, which should be considered
* supported for a modeling perspective.
*/
abstract class ApiSourceNode extends DataFlow::Node { }
private class AddSourceNodes extends ApiSourceNode instanceof SourceNode { }
/**
* Add all source models as data sources.
*/
private class ApiSourceNodeExternal extends ApiSourceNode {
ApiSourceNodeExternal() { sourceNode(this, _) }
}