Skip to content

Commit 2d93eea

Browse files
Covered deserialization filters in RmiUnsafeDeserialization.ql
1 parent e28f919 commit 2d93eea

File tree

1 file changed

+37
-21
lines changed

1 file changed

+37
-21
lines changed
Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/**
2-
* @name Unsafe deserialization with RMI.
2+
* @name Unsafe remote object.
33
* @description If a registered remote object has a method that accepts a complex object,
44
* an attacker can take advantage of the unsafe deserialization mechanism
55
* which is used to pass parameters in RMI.
66
* In the worst case, it results in remote code execution.
7-
* @kind problem
7+
* @kind path-problem
88
* @problem.severity error
99
* @precision high
1010
* @id java/unsafe-deserialization-rmi
@@ -13,11 +13,9 @@
1313
*/
1414

1515
import java
16+
import semmle.code.java.dataflow.TaintTracking
1617
import semmle.code.java.frameworks.Rmi
17-
18-
private class ObjectInputStream extends Class {
19-
ObjectInputStream() { hasQualifiedName("java.io", "ObjectInputStream") }
20-
}
18+
import DataFlow::PathGraph
2119

2220
/**
2321
* A method that binds a name to a remote object.
@@ -33,34 +31,52 @@ private class BindMethod extends Method {
3331
}
3432

3533
/**
36-
* Looks for a vulnerable method in a `Remote` object.
34+
* Holds if `type` has an unsafe remote method.
3735
*/
38-
private Method getVulnerableMethod(RefType type) {
36+
private predicate hasVulnerableMethod(RefType type) {
3937
exists(RemoteCallableMethod m, Type parameterType |
4038
m.getDeclaringType() = type and parameterType = m.getAParamType()
4139
|
4240
not parameterType instanceof PrimitiveType and
4341
not parameterType instanceof TypeString and
44-
not parameterType instanceof ObjectInputStream and
45-
result = m
42+
not parameterType.(RefType).hasQualifiedName("java.io", "ObjectInputStream")
4643
)
4744
}
4845

4946
/**
50-
* A method call that registers a remote object that has a vulnerable method.
47+
* A taint-tracking configuration for unsafe remote objects
48+
* that are vulnerable to deserialization attacks.
5149
*/
52-
private class UnsafeRmiBinding extends MethodAccess {
53-
Method vulnerableMethod;
50+
private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configuration {
51+
BindingUnsafeRemoteObjectConfig() { this = "BindingUnsafeRemoteObjectConfig" }
5452

55-
UnsafeRmiBinding() {
56-
this.getMethod() instanceof BindMethod and
57-
vulnerableMethod = getVulnerableMethod(this.getArgument(1).getType())
53+
override predicate isSource(DataFlow::Node source) {
54+
exists(ConstructorCall cc | cc = source.asExpr() |
55+
hasVulnerableMethod(cc.getConstructedType().getASupertype*())
56+
)
5857
}
5958

60-
Method getVulnerableMethod() { result = vulnerableMethod }
59+
override predicate isSink(DataFlow::Node sink) {
60+
exists(StaticMethodAccess ma | ma.getArgument(1) = sink.asExpr() |
61+
ma.getMethod() instanceof BindMethod
62+
)
63+
}
64+
65+
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
66+
exists(StaticMethodAccess ma, Method m | m = ma.getMethod() |
67+
m.getDeclaringType().hasQualifiedName("java.rmi.server", "UnicastRemoteObject") and
68+
m.hasName("exportObject") and
69+
not ma.getArgument([2, 4])
70+
.getType()
71+
.(RefType)
72+
.getASupertype*()
73+
.hasQualifiedName("java.io", "ObjectInputFilter") and
74+
ma.getArgument(0) = fromNode.asExpr() and
75+
ma = toNode.asExpr()
76+
)
77+
}
6178
}
6279

63-
from UnsafeRmiBinding call, Method vulnerableMethod
64-
where vulnerableMethod = call.getVulnerableMethod()
65-
select call, "Unsafe deserialization with RMI in '$@' method", vulnerableMethod,
66-
vulnerableMethod.getStringSignature()
80+
from DataFlow::PathNode source, DataFlow::PathNode sink, BindingUnsafeRemoteObjectConfig conf
81+
where conf.hasFlowPath(source, sink)
82+
select sink.getNode(), source, sink, "Binding an unsafe remote object."

0 commit comments

Comments
 (0)