Skip to content

Commit 0d5f911

Browse files
committed
Extract ldap injection sink into importable library
1 parent 2e5af67 commit 0d5f911

File tree

2 files changed

+108
-79
lines changed

2 files changed

+108
-79
lines changed

java/ql/src/Security/CWE/CWE-090/LdapInjectionLib.qll

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import java
22
import semmle.code.java.dataflow.FlowSources
33
import DataFlow
4-
import semmle.code.java.frameworks.Jndi
5-
import semmle.code.java.frameworks.UnboundId
6-
import semmle.code.java.frameworks.SpringLdap
7-
import semmle.code.java.frameworks.ApacheLdap
4+
import semmle.code.java.security.LdapInjection
85

96
/**
107
* A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries.
@@ -44,81 +41,6 @@ class LdapInjectionFlowConfig extends TaintTracking::Configuration {
4441
}
4542
}
4643

47-
/**
48-
* JNDI sink for LDAP injection vulnerabilities, i.e. 1st (DN) or 2nd (filter) argument to
49-
* `search` method from `DirContext`.
50-
*/
51-
predicate jndiLdapInjectionSinkMethod(Method m, int index) {
52-
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
53-
m.hasName("search") and
54-
index in [0 .. 1]
55-
}
56-
57-
/**
58-
* UnboundID sink for LDAP injection vulnerabilities,
59-
* i.e. LDAPConnection.search, LDAPConnection.asyncSearch or LDAPConnection.searchForEntry method.
60-
*/
61-
predicate unboundIdLdapInjectionSinkMethod(Method m, int index) {
62-
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
63-
m instanceof MethodUnboundIdLDAPConnectionSearch or
64-
m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
65-
m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
66-
)
67-
}
68-
69-
/**
70-
* Spring LDAP sink for LDAP injection vulnerabilities,
71-
* i.e. LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method.
72-
*/
73-
predicate springLdapInjectionSinkMethod(Method m, int index) {
74-
// LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
75-
(
76-
m instanceof MethodSpringLdapTemplateAuthenticate or
77-
m instanceof MethodSpringLdapTemplateFind or
78-
m instanceof MethodSpringLdapTemplateFindOne or
79-
m instanceof MethodSpringLdapTemplateSearch or
80-
m instanceof MethodSpringLdapTemplateSearchForContext or
81-
m instanceof MethodSpringLdapTemplateSearchForObject
82-
) and
83-
(
84-
// Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
85-
index in [0 .. 1] and
86-
not m instanceof MethodSpringLdapTemplateAuthenticate
87-
or
88-
// But it's not the last parameter in case of authenticate method (last param is password)
89-
index in [0 .. 1] and
90-
index < m.getNumberOfParameters() - 1 and
91-
m instanceof MethodSpringLdapTemplateAuthenticate
92-
)
93-
}
94-
95-
/** Apache LDAP API sink for LDAP injection vulnerabilities, i.e. LdapConnection.search method. */
96-
predicate apacheLdapInjectionSinkMethod(Method m, int index) {
97-
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
98-
m.getDeclaringType().getAnAncestor() instanceof TypeApacheLdapConnection and
99-
m.hasName("search")
100-
)
101-
}
102-
103-
/** Holds if parameter at index `index` in method `m` is LDAP injection sink. */
104-
predicate ldapInjectionSinkMethod(Method m, int index) {
105-
jndiLdapInjectionSinkMethod(m, index) or
106-
unboundIdLdapInjectionSinkMethod(m, index) or
107-
springLdapInjectionSinkMethod(m, index) or
108-
apacheLdapInjectionSinkMethod(m, index)
109-
}
110-
111-
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
112-
class LdapInjectionSink extends DataFlow::ExprNode {
113-
LdapInjectionSink() {
114-
exists(MethodAccess ma, Method m, int index |
115-
ma.getMethod() = m and
116-
ma.getArgument(index) = this.getExpr() and
117-
ldapInjectionSinkMethod(m, index)
118-
)
119-
}
120-
}
121-
12244
/**
12345
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName`,
12446
* i.e. `new LdapName(tainted)`.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/** Provides classes to reason about LDAP injection attacks. */
2+
3+
import java
4+
import semmle.code.java.dataflow.DataFlow
5+
import semmle.code.java.frameworks.Jndi
6+
import semmle.code.java.frameworks.UnboundId
7+
import semmle.code.java.frameworks.SpringLdap
8+
import semmle.code.java.frameworks.ApacheLdap
9+
10+
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
11+
abstract class LdapInjectionSink extends DataFlow::Node { }
12+
13+
private predicate jndiLdapInjectionSinkMethod(Method m, int index) {
14+
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
15+
m.hasName("search") and
16+
index in [0 .. 1]
17+
}
18+
19+
/**
20+
* JNDI sink for LDAP injection vulnerabilities, i.e. 1st (DN) or 2nd (filter) argument to
21+
* `search` method from `DirContext`.
22+
*/
23+
private class JndiLdapInjectionSink extends LdapInjectionSink {
24+
JndiLdapInjectionSink() {
25+
exists(MethodAccess ma, Method m, int index |
26+
ma.getMethod() = m and
27+
ma.getArgument(index) = this.asExpr() and
28+
jndiLdapInjectionSinkMethod(m, index)
29+
)
30+
}
31+
}
32+
33+
private predicate unboundIdLdapInjectionSinkMethod(Method m, int index) {
34+
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
35+
m instanceof MethodUnboundIdLDAPConnectionSearch or
36+
m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
37+
m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
38+
)
39+
}
40+
41+
/**
42+
* UnboundID sink for LDAP injection vulnerabilities,
43+
* i.e. LDAPConnection.search, LDAPConnection.asyncSearch or LDAPConnection.searchForEntry method.
44+
*/
45+
private class UnboundedIdLdapInjectionSink extends LdapInjectionSink {
46+
UnboundedIdLdapInjectionSink() {
47+
exists(MethodAccess ma, Method m, int index |
48+
ma.getMethod() = m and
49+
ma.getArgument(index) = this.asExpr() and
50+
unboundIdLdapInjectionSinkMethod(m, index)
51+
)
52+
}
53+
}
54+
55+
private predicate springLdapInjectionSinkMethod(Method m, int index) {
56+
// LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
57+
(
58+
m instanceof MethodSpringLdapTemplateAuthenticate or
59+
m instanceof MethodSpringLdapTemplateFind or
60+
m instanceof MethodSpringLdapTemplateFindOne or
61+
m instanceof MethodSpringLdapTemplateSearch or
62+
m instanceof MethodSpringLdapTemplateSearchForContext or
63+
m instanceof MethodSpringLdapTemplateSearchForObject
64+
) and
65+
(
66+
// Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
67+
index in [0 .. 1] and
68+
not m instanceof MethodSpringLdapTemplateAuthenticate
69+
or
70+
// But it's not the last parameter in case of authenticate method (last param is password)
71+
index in [0 .. 1] and
72+
index < m.getNumberOfParameters() - 1 and
73+
m instanceof MethodSpringLdapTemplateAuthenticate
74+
)
75+
}
76+
77+
/**
78+
* Spring LDAP sink for LDAP injection vulnerabilities,
79+
* i.e. LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method.
80+
*/
81+
private class SpringLdapInjectionSink extends LdapInjectionSink {
82+
SpringLdapInjectionSink() {
83+
exists(MethodAccess ma, Method m, int index |
84+
ma.getMethod() = m and
85+
ma.getArgument(index) = this.asExpr() and
86+
springLdapInjectionSinkMethod(m, index)
87+
)
88+
}
89+
}
90+
91+
private predicate apacheLdapInjectionSinkMethod(Method m, int index) {
92+
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
93+
m.getDeclaringType().getAnAncestor() instanceof TypeApacheLdapConnection and
94+
m.hasName("search")
95+
)
96+
}
97+
98+
/** Apache LDAP API sink for LDAP injection vulnerabilities, i.e. LdapConnection.search method. */
99+
private class ApacheLdapInjectionSink extends LdapInjectionSink {
100+
ApacheLdapInjectionSink() {
101+
exists(MethodAccess ma, Method m, int index |
102+
ma.getMethod() = m and
103+
ma.getArgument(index) = this.asExpr() and
104+
apacheLdapInjectionSinkMethod(m, index)
105+
)
106+
}
107+
}

0 commit comments

Comments
 (0)