1
1
/**
2
- * @name Unsafe deserialization with RMI .
2
+ * @name Unsafe remote object .
3
3
* @description If a registered remote object has a method that accepts a complex object,
4
4
* an attacker can take advantage of the unsafe deserialization mechanism
5
5
* which is used to pass parameters in RMI.
6
6
* In the worst case, it results in remote code execution.
7
- * @kind problem
7
+ * @kind path- problem
8
8
* @problem.severity error
9
9
* @precision high
10
10
* @id java/unsafe-deserialization-rmi
13
13
*/
14
14
15
15
import java
16
+ import semmle.code.java.dataflow.TaintTracking
16
17
import semmle.code.java.frameworks.Rmi
17
-
18
- private class ObjectInputStream extends Class {
19
- ObjectInputStream ( ) { hasQualifiedName ( "java.io" , "ObjectInputStream" ) }
20
- }
18
+ import DataFlow:: PathGraph
21
19
22
20
/**
23
21
* A method that binds a name to a remote object.
@@ -33,34 +31,52 @@ private class BindMethod extends Method {
33
31
}
34
32
35
33
/**
36
- * Looks for a vulnerable method in a `Remote` object .
34
+ * Holds if `type` has an unsafe remote method .
37
35
*/
38
- private Method getVulnerableMethod ( RefType type ) {
36
+ private predicate hasVulnerableMethod ( RefType type ) {
39
37
exists ( RemoteCallableMethod m , Type parameterType |
40
38
m .getDeclaringType ( ) = type and parameterType = m .getAParamType ( )
41
39
|
42
40
not parameterType instanceof PrimitiveType and
43
41
not parameterType instanceof TypeString and
44
- not parameterType instanceof ObjectInputStream and
45
- result = m
42
+ not parameterType .( RefType ) .hasQualifiedName ( "java.io" , "ObjectInputStream" )
46
43
)
47
44
}
48
45
49
46
/**
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.
51
49
*/
52
- private class UnsafeRmiBinding extends MethodAccess {
53
- Method vulnerableMethod ;
50
+ private class BindingUnsafeRemoteObjectConfig extends TaintTracking :: Configuration {
51
+ BindingUnsafeRemoteObjectConfig ( ) { this = "BindingUnsafeRemoteObjectConfig" }
54
52
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
+ )
58
57
}
59
58
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
+ }
61
78
}
62
79
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