-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathUnsafeDeserialization.qll
More file actions
79 lines (72 loc) · 2.84 KB
/
UnsafeDeserialization.qll
File metadata and controls
79 lines (72 loc) · 2.84 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
/**
* This is a copy of UnsafeDeserialization.qll from the QL standard library
* for Java. It is copied here for the purpose of recreating the scenario
* when Mo first discovered the vulnerability. At the time, the standard
* unsafe deserialization query (UnsafeDeserialization.ql) did not detect the
* bug. Mo discovered the vulnerability by customizing the standard query,
* using knowledge that he had about the design of Struts. (The standard query
* has since been improved so that it will automatically detect similar
* vulnerabilities in future.)
*/
import semmle.code.java.frameworks.Kryo
import semmle.code.java.frameworks.XStream
import semmle.code.java.dataflow.DataFlow
class ObjectInputStreamReadObjectMethod extends Method {
ObjectInputStreamReadObjectMethod() {
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.io", "ObjectInputStream") and
(this.hasName("readObject") or this.hasName("readUnshared"))
}
}
class XMLDecoderReadObjectMethod extends Method {
XMLDecoderReadObjectMethod() {
this.getDeclaringType().hasQualifiedName("java.beans", "XMLDecoder") and
this.hasName("readObject")
}
}
class SafeXStream extends DataFlow::Configuration {
SafeXStream() { this = "UnsafeDeserialization::SafeXStream" }
override predicate isSource(DataFlow::Node src) {
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src.asExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
ma.getMethod() instanceof XStreamReadObjectMethod
)
}
}
class SafeKryo extends DataFlow::Configuration {
SafeKryo() { this = "UnsafeDeserialization::SafeKryo" }
override predicate isSource(DataFlow::Node src) {
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src.asExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
ma.getMethod() instanceof KryoReadObjectMethod
)
}
}
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
exists(Method m | m = ma.getMethod() |
m instanceof ObjectInputStreamReadObjectMethod and
sink = ma.getQualifier()
or
m instanceof XMLDecoderReadObjectMethod and
sink = ma.getQualifier()
or
m instanceof XStreamReadObjectMethod and
sink = ma.getAnArgument() and
not exists(SafeXStream sxs | sxs.hasFlowToExpr(ma.getQualifier()))
or
m instanceof KryoReadObjectMethod and
sink = ma.getAnArgument() and
not exists(SafeKryo sk | sk.hasFlowToExpr(ma.getQualifier()))
)
}
class UnsafeDeserializationSink extends DataFlow::ExprNode {
UnsafeDeserializationSink() {
unsafeDeserialization(_, this.getExpr())
}
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
}