@@ -3,6 +3,7 @@ import semmle.code.java.dataflow.FlowSources
3
3
import DataFlow
4
4
import experimental.semmle.code.java.frameworks.Jndi
5
5
import experimental.semmle.code.java.frameworks.spring.SpringJndi
6
+ import semmle.code.java.frameworks.SpringLdap
6
7
import experimental.semmle.code.java.frameworks.Shiro
7
8
8
9
/**
@@ -20,10 +21,35 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration {
20
21
}
21
22
22
23
override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
23
- compositeNameStep ( node1 , node2 )
24
+ compositeNameStep ( node1 , node2 ) or
25
+ jmxServiceUrlStep ( node1 , node2 ) or
26
+ jmxConnectorStep ( node1 , node2 ) or
27
+ rmiConnectorStep ( node1 , node2 )
24
28
}
25
29
}
26
30
31
+ /** The interface `javax.management.remote.JMXConnector`. */
32
+ class TypeJMXConnector extends Interface {
33
+ TypeJMXConnector ( ) { this .hasQualifiedName ( "javax.management.remote" , "JMXConnector" ) }
34
+ }
35
+
36
+ /** The class `javax.management.remote.rmi.RMIConnector`. */
37
+ class TypeRMIConnector extends Class {
38
+ TypeRMIConnector ( ) { this .hasQualifiedName ( "javax.management.remote.rmi" , "RMIConnector" ) }
39
+ }
40
+
41
+ /** The class `javax.management.remote.JMXConnectorFactory`. */
42
+ class TypeJMXConnectorFactory extends Class {
43
+ TypeJMXConnectorFactory ( ) {
44
+ this .hasQualifiedName ( "javax.management.remote" , "JMXConnectorFactory" )
45
+ }
46
+ }
47
+
48
+ /** The class `javax.management.remote.JMXServiceURL`. */
49
+ class TypeJMXServiceURL extends Class {
50
+ TypeJMXServiceURL ( ) { this .hasQualifiedName ( "javax.management.remote" , "JMXServiceURL" ) }
51
+ }
52
+
27
53
/**
28
54
* JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`,
29
55
* `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`.
@@ -45,12 +71,22 @@ predicate jndiSinkMethod(Method m, int index) {
45
71
* Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
46
72
* Spring's `JndiTemplate`.
47
73
*/
48
- predicate springSinkMethod ( Method m , int index ) {
74
+ predicate springJndiTemplateSinkMethod ( Method m , int index ) {
49
75
m .getDeclaringType ( ) instanceof TypeSpringJndiTemplate and
50
76
m .hasName ( "lookup" ) and
51
77
index = 0
52
78
}
53
79
80
+ /**
81
+ * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` or `lookupContext`
82
+ * method from Spring's `LdapTemplate`.
83
+ */
84
+ predicate springLdapTemplateSinkMethod ( Method m , int index ) {
85
+ m .getDeclaringType ( ) instanceof TypeSpringLdapTemplate and
86
+ ( m .hasName ( "lookup" ) or m .hasName ( "lookupContext" ) ) and
87
+ index = 0
88
+ }
89
+
54
90
/**
55
91
* Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
56
92
* Shiro's `JndiTemplate`.
@@ -61,11 +97,23 @@ predicate shiroSinkMethod(Method m, int index) {
61
97
index = 0
62
98
}
63
99
100
+ /**
101
+ * `JMXConnectorFactory` sink for JNDI injection vulnerabilities, i.e. 1st argument to `connect`
102
+ * method from `JMXConnectorFactory`.
103
+ */
104
+ predicate jmxConnectorFactorySinkMethod ( Method m , int index ) {
105
+ m .getDeclaringType ( ) instanceof TypeJMXConnectorFactory and
106
+ m .hasName ( "connect" ) and
107
+ index = 0
108
+ }
109
+
64
110
/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */
65
111
predicate jndiInjectionSinkMethod ( Method m , int index ) {
66
112
jndiSinkMethod ( m , index ) or
67
- springSinkMethod ( m , index ) or
68
- shiroSinkMethod ( m , index )
113
+ springJndiTemplateSinkMethod ( m , index ) or
114
+ springLdapTemplateSinkMethod ( m , index ) or
115
+ shiroSinkMethod ( m , index ) or
116
+ jmxConnectorFactorySinkMethod ( m , index )
69
117
}
70
118
71
119
/** A data flow sink for unvalidated user input that is used in JNDI lookup. */
@@ -76,6 +124,13 @@ class JndiInjectionSink extends DataFlow::ExprNode {
76
124
ma .getArgument ( index ) = this .getExpr ( ) and
77
125
jndiInjectionSinkMethod ( m , index )
78
126
)
127
+ or
128
+ exists ( MethodAccess ma , Method m |
129
+ ma .getMethod ( ) = m and
130
+ ma .getQualifier ( ) = this .getExpr ( ) and
131
+ m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeJMXConnector and
132
+ m .hasName ( "connect" )
133
+ )
79
134
}
80
135
}
81
136
@@ -89,3 +144,37 @@ predicate compositeNameStep(ExprNode n1, ExprNode n2) {
89
144
n2 .asExpr ( ) = cc
90
145
)
91
146
}
147
+
148
+ /**
149
+ * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`,
150
+ * i.e. `new JMXServiceURL(tainted)`.
151
+ */
152
+ predicate jmxServiceUrlStep ( ExprNode n1 , ExprNode n2 ) {
153
+ exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeJMXServiceURL |
154
+ n1 .asExpr ( ) = cc .getAnArgument ( ) and
155
+ n2 .asExpr ( ) = cc
156
+ )
157
+ }
158
+
159
+ /**
160
+ * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
161
+ * `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`.
162
+ */
163
+ predicate jmxConnectorStep ( ExprNode n1 , ExprNode n2 ) {
164
+ exists ( MethodAccess ma , Method m | n1 .asExpr ( ) = ma .getArgument ( 0 ) and n2 .asExpr ( ) = ma |
165
+ ma .getMethod ( ) = m and
166
+ m .getDeclaringType ( ) instanceof TypeJMXConnectorFactory and
167
+ m .hasName ( "newJMXConnector" )
168
+ )
169
+ }
170
+
171
+ /**
172
+ * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
173
+ * `RMIConnector`, i.e. `new RMIConnector(tainted)`.
174
+ */
175
+ predicate rmiConnectorStep ( ExprNode n1 , ExprNode n2 ) {
176
+ exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeRMIConnector |
177
+ n1 .asExpr ( ) = cc .getAnArgument ( ) and
178
+ n2 .asExpr ( ) = cc
179
+ )
180
+ }
0 commit comments