Skip to content

Commit 9362ae0

Browse files
authored
Merge pull request github#5422 from tamasvajk/feature/sink-migration-ldap
Java: Migrate LDAP injection sinks to CSV format
2 parents 7080b25 + 583513b commit 9362ae0

File tree

2 files changed

+48
-60
lines changed

2 files changed

+48
-60
lines changed

java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ private module Frameworks {
7777
private import semmle.code.java.frameworks.ApacheHttp
7878
private import semmle.code.java.frameworks.apache.Lang
7979
private import semmle.code.java.frameworks.guava.Guava
80+
private import semmle.code.java.security.LdapInjection
8081
}
8182

8283
private predicate sourceModelCsv(string row) {

java/ql/src/semmle/code/java/security/LdapInjection.qll

Lines changed: 47 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.Jndi
66
import semmle.code.java.frameworks.UnboundId
77
import semmle.code.java.frameworks.SpringLdap
88
import 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. */
1112
abstract class LdapInjectionSink extends DataFlow::Node { }
@@ -28,68 +29,54 @@ class LdapInjectionAdditionalTaintStep extends Unit {
2829

2930
/** Default sink for LDAP injection vulnerabilities. */
3031
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") }
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

Comments
 (0)