@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.Jndi
66import semmle.code.java.frameworks.UnboundId
77import semmle.code.java.frameworks.SpringLdap
88import semmle.code.java.frameworks.ApacheLdap
9+ private import semmle.code.java.dataflow.ExternalFlow
910
1011/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
1112abstract class LdapInjectionSink extends DataFlow:: Node { }
@@ -28,68 +29,54 @@ class LdapInjectionAdditionalTaintStep extends Unit {
2829
2930/** Default sink for LDAP injection vulnerabilities. */
3031private 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" ) }
6233}
6334
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+ }
9380}
9481
9582/** A sanitizer that clears the taint on (boxed) primitive types. */
0 commit comments