@@ -21,10 +21,32 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration {
2121 }
2222
2323 override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
24- compositeNameStep ( node1 , node2 ) or
24+ nameStep ( node1 , node2 ) or
2525 jmxServiceUrlStep ( node1 , node2 ) or
2626 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>" )
2850 }
2951}
3052
@@ -50,6 +72,11 @@ class TypeJMXServiceURL extends Class {
5072 TypeJMXServiceURL ( ) { this .hasQualifiedName ( "javax.management.remote" , "JMXServiceURL" ) }
5173}
5274
75+ /** The interface `javax.naming.Context`. */
76+ class TypeNamingContext extends Interface {
77+ TypeNamingContext ( ) { this .hasQualifiedName ( "javax.naming" , "Context" ) }
78+ }
79+
5380/**
5481 * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`,
5582 * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`.
@@ -73,17 +100,38 @@ predicate jndiSinkMethod(Method m, int index) {
73100 */
74101predicate springJndiTemplateSinkMethod ( Method m , int index ) {
75102 m .getDeclaringType ( ) instanceof TypeSpringJndiTemplate and
76- m .hasName ( "lookup" ) and
103+ ( m .hasName ( "lookup" ) or m . hasName ( "setEnvironment" ) ) and
77104 index = 0
78105}
79106
80107/**
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`.
83111 */
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
87135 index = 0
88136}
89137
@@ -108,10 +156,10 @@ predicate jmxConnectorFactorySinkMethod(Method m, int index) {
108156}
109157
110158/** 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 ) {
112160 jndiSinkMethod ( m , index ) or
113161 springJndiTemplateSinkMethod ( m , index ) or
114- springLdapTemplateSinkMethod ( m , index ) or
162+ springLdapTemplateSinkMethod ( ma , m , index ) or
115163 shiroSinkMethod ( m , index ) or
116164 jmxConnectorFactorySinkMethod ( m , index )
117165}
@@ -122,7 +170,7 @@ class JndiInjectionSink extends DataFlow::ExprNode {
122170 exists ( MethodAccess ma , Method m , int index |
123171 ma .getMethod ( ) = m and
124172 ma .getArgument ( index ) = this .getExpr ( ) and
125- jndiInjectionSinkMethod ( m , index )
173+ jndiInjectionSinkMethod ( ma , m , index )
126174 )
127175 or
128176 exists ( MethodAccess ma , Method m |
@@ -131,15 +179,25 @@ class JndiInjectionSink extends DataFlow::ExprNode {
131179 m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeJMXConnector and
132180 m .hasName ( "connect" )
133181 )
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+ )
134189 }
135190}
136191
137192/**
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)`.
140195 */
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+ |
143201 n1 .asExpr ( ) = cc .getAnArgument ( ) and
144202 n2 .asExpr ( ) = cc
145203 )
@@ -178,3 +236,27 @@ predicate rmiConnectorStep(ExprNode n1, ExprNode n2) {
178236 n2 .asExpr ( ) = cc
179237 )
180238}
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