@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.Jndi
6
6
import semmle.code.java.frameworks.UnboundId
7
7
import semmle.code.java.frameworks.SpringLdap
8
8
import semmle.code.java.frameworks.ApacheLdap
9
+ private import semmle.code.java.dataflow.ExternalFlow
9
10
10
11
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
11
12
abstract class LdapInjectionSink extends DataFlow:: Node { }
@@ -28,68 +29,54 @@ class LdapInjectionAdditionalTaintStep extends Unit {
28
29
29
30
/** Default sink for LDAP injection vulnerabilities. */
30
31
private class DefaultLdapInjectionSink extends LdapInjectionSink {
31
- DefaultLdapInjectionSink ( ) {
32
- exists ( MethodAccess ma , Method m , int index |
33
- ma .getMethod ( ) = m and
34
- ma .getArgument ( index ) = this .asExpr ( ) and
35
- ldapInjectionSinkMethod ( m , index )
36
- )
37
- }
38
- }
39
-
40
- /** Holds if the method parameter at `index` is susceptible to an LDAP injection attack. */
41
- private predicate ldapInjectionSinkMethod ( Method m , int index ) {
42
- jndiLdapInjectionSinkMethod ( m , index ) or
43
- unboundIdLdapInjectionSinkMethod ( m , index ) or
44
- springLdapInjectionSinkMethod ( m , index ) or
45
- apacheLdapInjectionSinkMethod ( m , index )
46
- }
47
-
48
- /** Holds if the JNDI method parameter at `index` is susceptible to an LDAP injection attack. */
49
- private predicate jndiLdapInjectionSinkMethod ( Method m , int index ) {
50
- m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeDirContext and
51
- m .hasName ( "search" ) and
52
- index in [ 0 .. 1 ]
53
- }
54
-
55
- /** Holds if the UnboundID method parameter at `index` is susceptible to an LDAP injection attack. */
56
- private predicate unboundIdLdapInjectionSinkMethod ( Method m , int index ) {
57
- exists ( Parameter param | m .getParameter ( index ) = param and not param .isVarargs ( ) |
58
- m instanceof MethodUnboundIdLDAPConnectionSearch or
59
- m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
60
- m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
61
- )
32
+ DefaultLdapInjectionSink ( ) { sinkNode ( this , "ldap" ) }
62
33
}
63
34
64
- /** Holds if the Spring method parameter at `index` is susceptible to an LDAP injection attack. */
65
- private predicate springLdapInjectionSinkMethod ( Method m , int index ) {
66
- // LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
67
- (
68
- m instanceof MethodSpringLdapTemplateAuthenticate or
69
- m instanceof MethodSpringLdapTemplateFind or
70
- m instanceof MethodSpringLdapTemplateFindOne or
71
- m instanceof MethodSpringLdapTemplateSearch or
72
- m instanceof MethodSpringLdapTemplateSearchForContext or
73
- m instanceof MethodSpringLdapTemplateSearchForObject
74
- ) and
75
- (
76
- // Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
77
- index in [ 0 .. 1 ] and
78
- not m instanceof MethodSpringLdapTemplateAuthenticate
79
- or
80
- // But it's not the last parameter in case of authenticate method (last param is password)
81
- index in [ 0 .. 1 ] and
82
- index < m .getNumberOfParameters ( ) - 1 and
83
- m instanceof MethodSpringLdapTemplateAuthenticate
84
- )
85
- }
86
-
87
- /** Holds if the Apache LDAP API method parameter at `index` is susceptible to an LDAP injection attack. */
88
- private predicate apacheLdapInjectionSinkMethod ( Method m , int index ) {
89
- exists ( Parameter param | m .getParameter ( index ) = param and not param .isVarargs ( ) |
90
- m .getDeclaringType ( ) .getAnAncestor ( ) instanceof TypeApacheLdapConnection and
91
- m .hasName ( "search" )
92
- )
35
+ private class DefaultLdapInjectionSinkModel extends SinkModelCsv {
36
+ override predicate row ( string row ) {
37
+ row =
38
+ [
39
+ // jndi
40
+ "javax.naming.directory;DirContext;true;search;;;Argument[0..1];ldap" ,
41
+ // apache
42
+ "org.apache.directory.ldap.client.api;LdapConnection;true;search;;;Argument[0..2];ldap" ,
43
+ // UnboundID: search
44
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(ReadOnlySearchRequest);;Argument[0];ldap" ,
45
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchRequest);;Argument[0];ldap" ,
46
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,DereferencePolicy,int,int,boolean,Filter,String[]);;Argument[0..7];ldap" ,
47
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,DereferencePolicy,int,int,boolean,String,String[]);;Argument[0..7];ldap" ,
48
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,Filter,String[]);;Argument[0..3];ldap" ,
49
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(SearchResultListener,String,SearchScope,String,String[]);;Argument[0..3];ldap" ,
50
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,DereferencePolicy,int,int,boolean,Filter,String[]);;Argument[0..6];ldap" ,
51
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,DereferencePolicy,int,int,boolean,String,String[]);;Argument[0..6];ldap" ,
52
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,Filter,String[]);;Argument[0..2];ldap" ,
53
+ "com.unboundid.ldap.sdk;LDAPConnection;false;search;(String,SearchScope,String,String[]);;Argument[0..2];ldap" ,
54
+ // UnboundID: searchForEntry
55
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(ReadOnlySearchRequest);;Argument[0];ldap" ,
56
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(SearchRequest);;Argument[0];ldap" ,
57
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,DereferencePolicy,int,boolean,Filter,String[]);;Argument[0..5];ldap" ,
58
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,DereferencePolicy,int,boolean,String,String[]);;Argument[0..5];ldap" ,
59
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,Filter,String[]);;Argument[0..2];ldap" ,
60
+ "com.unboundid.ldap.sdk;LDAPConnection;false;searchForEntry;(String,SearchScope,String,String[]);;Argument[0..2];ldap" ,
61
+ // UnboundID: asyncSearch
62
+ "com.unboundid.ldap.sdk;LDAPConnection;false;asyncSearch;;;Argument[0];ldap" ,
63
+ // Spring
64
+ "org.springframework.ldap.core;LdapTemplate;false;find;;;Argument[0..1];ldap" ,
65
+ "org.springframework.ldap.core;LdapTemplate;false;findOne;;;Argument[0..1];ldap" ,
66
+ "org.springframework.ldap.core;LdapTemplate;false;search;;;Argument[0..1];ldap" ,
67
+ "org.springframework.ldap.core;LdapTemplate;false;searchForContext;;;Argument[0..1];ldap" ,
68
+ "org.springframework.ldap.core;LdapTemplate;false;searchForObject;;;Argument[0..1];ldap" ,
69
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(LdapQuery,String);;Argument[0];ldap" ,
70
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String);;Argument[0..1];ldap" ,
71
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticatedLdapEntryContextCallback);;Argument[0..1];ldap" ,
72
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticatedLdapEntryContextCallback,AuthenticationErrorCallback);;Argument[0..1];ldap" ,
73
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(Name,String,String,AuthenticationErrorCallback);;Argument[0..1];ldap" ,
74
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String);;Argument[0..1];ldap" ,
75
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticatedLdapEntryContextCallback);;Argument[0..1];ldap" ,
76
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticatedLdapEntryContextCallback,AuthenticationErrorCallback);;Argument[0..1];ldap" ,
77
+ "org.springframework.ldap.core;LdapTemplate;false;authenticate;(String,String,String,AuthenticationErrorCallback);;Argument[0..1];ldap"
78
+ ]
79
+ }
93
80
}
94
81
95
82
/** A sanitizer that clears the taint on (boxed) primitive types. */
0 commit comments