@@ -21,10 +21,32 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration {
21
21
}
22
22
23
23
override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
24
- compositeNameStep ( node1 , node2 ) or
24
+ nameStep ( node1 , node2 ) or
25
25
jmxServiceUrlStep ( node1 , node2 ) or
26
26
jmxConnectorStep ( node1 , node2 ) or
27
- rmiConnectorStep ( node1 , node2 )
27
+ rmiConnectorStep ( node1 , node2 ) or
28
+ providerUrlEnvStep ( node1 , node2 )
29
+ }
30
+ }
31
+
32
+ /** The class `javax.naming.directory.SearchControls`. */
33
+ class TypeSearchControls extends Class {
34
+ TypeSearchControls ( ) { this .hasQualifiedName ( "javax.naming.directory" , "SearchControls" ) }
35
+ }
36
+
37
+ /** The interface `org.springframework.ldap.core.LdapOperations`. */
38
+ class TypeSpringLdapOperations extends Interface {
39
+ TypeSpringLdapOperations ( ) {
40
+ this .hasQualifiedName ( "org.springframework.ldap.core" , "LdapOperations" ) or
41
+ this .hasQualifiedName ( "org.springframework.ldap" , "LdapOperations" )
42
+ }
43
+ }
44
+
45
+ /** The interface `org.springframework.ldap.core.ContextMapper`. */
46
+ class TypeSpringContextMapper extends Interface {
47
+ TypeSpringContextMapper ( ) {
48
+ this .hasQualifiedName ( "org.springframework.ldap.core" , "ContextMapper<T>" ) or
49
+ this .hasQualifiedName ( "org.springframework.ldap" , "ContextMapper<T>" )
28
50
}
29
51
}
30
52
@@ -50,6 +72,11 @@ class TypeJMXServiceURL extends Class {
50
72
TypeJMXServiceURL ( ) { this .hasQualifiedName ( "javax.management.remote" , "JMXServiceURL" ) }
51
73
}
52
74
75
+ /** The interface `javax.naming.Context`. */
76
+ class TypeNamingContext extends Interface {
77
+ TypeNamingContext ( ) { this .hasQualifiedName ( "javax.naming" , "Context" ) }
78
+ }
79
+
53
80
/**
54
81
* JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`,
55
82
* `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`.
@@ -73,17 +100,38 @@ predicate jndiSinkMethod(Method m, int index) {
73
100
*/
74
101
predicate springJndiTemplateSinkMethod ( Method m , int index ) {
75
102
m .getDeclaringType ( ) instanceof TypeSpringJndiTemplate and
76
- m .hasName ( "lookup" ) and
103
+ ( m .hasName ( "lookup" ) or m . hasName ( "setEnvironment" ) ) and
77
104
index = 0
78
105
}
79
106
80
107
/**
81
- * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` or `lookupContext`
82
- * method from Spring's `LdapTemplate`.
108
+ * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupContext`,
109
+ * `findByDn`, `rename`, `list`, `listBindings`, `unbind`, `search` or `searchForObject` method
110
+ * from Spring's `LdapOperations`.
83
111
*/
84
- predicate springLdapTemplateSinkMethod ( Method m , int index ) {
85
- m .getDeclaringType ( ) instanceof TypeSpringLdapTemplate and
86
- ( m .hasName ( "lookup" ) or m .hasName ( "lookupContext" ) ) and
112
+ predicate springLdapTemplateSinkMethod ( MethodAccess ma , Method m , int index ) {
113
+ m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeSpringLdapOperations and
114
+ (
115
+ m .hasName ( "lookup" )
116
+ or
117
+ m .hasName ( "lookupContext" )
118
+ or
119
+ m .hasName ( "findByDn" )
120
+ or
121
+ m .hasName ( "rename" )
122
+ or
123
+ m .hasName ( "list" )
124
+ or
125
+ m .hasName ( "listBindings" )
126
+ or
127
+ m .hasName ( "unbind" ) and ma .getArgument ( 1 ) .( CompileTimeConstantExpr ) .getBooleanValue ( ) = true
128
+ or
129
+ m .getName ( ) .matches ( "search%" ) and
130
+ m .getParameterType ( m .getNumberOfParameters ( ) - 1 ) instanceof TypeSpringContextMapper and
131
+ not m .getAParamType ( ) instanceof TypeSearchControls
132
+ or
133
+ m .hasName ( "search" ) and ma .getArgument ( 3 ) .( CompileTimeConstantExpr ) .getBooleanValue ( ) = true
134
+ ) and
87
135
index = 0
88
136
}
89
137
@@ -108,10 +156,10 @@ predicate jmxConnectorFactorySinkMethod(Method m, int index) {
108
156
}
109
157
110
158
/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */
111
- predicate jndiInjectionSinkMethod ( Method m , int index ) {
159
+ predicate jndiInjectionSinkMethod ( MethodAccess ma , Method m , int index ) {
112
160
jndiSinkMethod ( m , index ) or
113
161
springJndiTemplateSinkMethod ( m , index ) or
114
- springLdapTemplateSinkMethod ( m , index ) or
162
+ springLdapTemplateSinkMethod ( ma , m , index ) or
115
163
shiroSinkMethod ( m , index ) or
116
164
jmxConnectorFactorySinkMethod ( m , index )
117
165
}
@@ -122,7 +170,7 @@ class JndiInjectionSink extends DataFlow::ExprNode {
122
170
exists ( MethodAccess ma , Method m , int index |
123
171
ma .getMethod ( ) = m and
124
172
ma .getArgument ( index ) = this .getExpr ( ) and
125
- jndiInjectionSinkMethod ( m , index )
173
+ jndiInjectionSinkMethod ( ma , m , index )
126
174
)
127
175
or
128
176
exists ( MethodAccess ma , Method m |
@@ -131,15 +179,25 @@ class JndiInjectionSink extends DataFlow::ExprNode {
131
179
m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeJMXConnector and
132
180
m .hasName ( "connect" )
133
181
)
182
+ or
183
+ exists ( ConstructorCall cc |
184
+ cc .getConstructedType ( ) .getAnAncestor ( ) instanceof TypeInitialContext or
185
+ cc .getConstructedType ( ) instanceof TypeSpringJndiTemplate
186
+ |
187
+ cc .getArgument ( 0 ) = this .getExpr ( )
188
+ )
134
189
}
135
190
}
136
191
137
192
/**
138
- * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName`,
139
- * i.e. `new CompositeName(tainted)`.
193
+ * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName` or
194
+ * `CompoundName`, i.e. `new CompositeName(tainted)` or `new CompoundName (tainted)`.
140
195
*/
141
- predicate compositeNameStep ( ExprNode n1 , ExprNode n2 ) {
142
- exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeCompositeName |
196
+ predicate nameStep ( ExprNode n1 , ExprNode n2 ) {
197
+ exists ( ConstructorCall cc |
198
+ cc .getConstructedType ( ) instanceof TypeCompositeName or
199
+ cc .getConstructedType ( ) instanceof TypeCompoundName
200
+ |
143
201
n1 .asExpr ( ) = cc .getAnArgument ( ) and
144
202
n2 .asExpr ( ) = cc
145
203
)
@@ -178,3 +236,27 @@ predicate rmiConnectorStep(ExprNode n1, ExprNode n2) {
178
236
n2 .asExpr ( ) = cc
179
237
)
180
238
}
239
+
240
+ /**
241
+ * Holds if `n1` to `n2` is a dataflow step that converts between `String` and
242
+ * `Hashtable` or `Properties`, i.e. `env.put(Context.PROVIDER_URL, tainted)` or
243
+ * `env.setProperty(Context.PROVIDER_URL, tainted)`.
244
+ */
245
+ predicate providerUrlEnvStep ( ExprNode n1 , ExprNode n2 ) {
246
+ exists ( MethodAccess ma , Method m |
247
+ n1 .asExpr ( ) = ma .getArgument ( 1 ) and n2 .asExpr ( ) = ma .getQualifier ( )
248
+ |
249
+ ma .getMethod ( ) = m and
250
+ m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeProperty and
251
+ ( m .hasName ( "put" ) or m .hasName ( "setProperty" ) ) and
252
+ (
253
+ ma .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "java.naming.provider.url"
254
+ or
255
+ exists ( Field f |
256
+ ma .getArgument ( 0 ) = f .getAnAccess ( ) and
257
+ f .hasName ( "PROVIDER_URL" ) and
258
+ f .getDeclaringType ( ) instanceof TypeNamingContext
259
+ )
260
+ )
261
+ )
262
+ }
0 commit comments