mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
Extract ldap injection sink into importable library
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow
|
||||
import semmle.code.java.frameworks.Jndi
|
||||
import semmle.code.java.frameworks.UnboundId
|
||||
import semmle.code.java.frameworks.SpringLdap
|
||||
import semmle.code.java.frameworks.ApacheLdap
|
||||
import semmle.code.java.security.LdapInjection
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries.
|
||||
@@ -44,81 +41,6 @@ class LdapInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JNDI sink for LDAP injection vulnerabilities, i.e. 1st (DN) or 2nd (filter) argument to
|
||||
* `search` method from `DirContext`.
|
||||
*/
|
||||
predicate jndiLdapInjectionSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
|
||||
m.hasName("search") and
|
||||
index in [0 .. 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* UnboundID sink for LDAP injection vulnerabilities,
|
||||
* i.e. LDAPConnection.search, LDAPConnection.asyncSearch or LDAPConnection.searchForEntry method.
|
||||
*/
|
||||
predicate unboundIdLdapInjectionSinkMethod(Method m, int index) {
|
||||
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
|
||||
m instanceof MethodUnboundIdLDAPConnectionSearch or
|
||||
m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
|
||||
m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring LDAP sink for LDAP injection vulnerabilities,
|
||||
* i.e. LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method.
|
||||
*/
|
||||
predicate springLdapInjectionSinkMethod(Method m, int index) {
|
||||
// LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
|
||||
(
|
||||
m instanceof MethodSpringLdapTemplateAuthenticate or
|
||||
m instanceof MethodSpringLdapTemplateFind or
|
||||
m instanceof MethodSpringLdapTemplateFindOne or
|
||||
m instanceof MethodSpringLdapTemplateSearch or
|
||||
m instanceof MethodSpringLdapTemplateSearchForContext or
|
||||
m instanceof MethodSpringLdapTemplateSearchForObject
|
||||
) and
|
||||
(
|
||||
// Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
|
||||
index in [0 .. 1] and
|
||||
not m instanceof MethodSpringLdapTemplateAuthenticate
|
||||
or
|
||||
// But it's not the last parameter in case of authenticate method (last param is password)
|
||||
index in [0 .. 1] and
|
||||
index < m.getNumberOfParameters() - 1 and
|
||||
m instanceof MethodSpringLdapTemplateAuthenticate
|
||||
)
|
||||
}
|
||||
|
||||
/** Apache LDAP API sink for LDAP injection vulnerabilities, i.e. LdapConnection.search method. */
|
||||
predicate apacheLdapInjectionSinkMethod(Method m, int index) {
|
||||
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeApacheLdapConnection and
|
||||
m.hasName("search")
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if parameter at index `index` in method `m` is LDAP injection sink. */
|
||||
predicate ldapInjectionSinkMethod(Method m, int index) {
|
||||
jndiLdapInjectionSinkMethod(m, index) or
|
||||
unboundIdLdapInjectionSinkMethod(m, index) or
|
||||
springLdapInjectionSinkMethod(m, index) or
|
||||
apacheLdapInjectionSinkMethod(m, index)
|
||||
}
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
|
||||
class LdapInjectionSink extends DataFlow::ExprNode {
|
||||
LdapInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.getExpr() and
|
||||
ldapInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName`,
|
||||
* i.e. `new LdapName(tainted)`.
|
||||
|
||||
107
java/ql/src/semmle/code/java/security/LdapInjection.qll
Normal file
107
java/ql/src/semmle/code/java/security/LdapInjection.qll
Normal file
@@ -0,0 +1,107 @@
|
||||
/** Provides classes to reason about LDAP injection attacks. */
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.frameworks.Jndi
|
||||
import semmle.code.java.frameworks.UnboundId
|
||||
import semmle.code.java.frameworks.SpringLdap
|
||||
import semmle.code.java.frameworks.ApacheLdap
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
|
||||
abstract class LdapInjectionSink extends DataFlow::Node { }
|
||||
|
||||
private predicate jndiLdapInjectionSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeDirContext and
|
||||
m.hasName("search") and
|
||||
index in [0 .. 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* JNDI sink for LDAP injection vulnerabilities, i.e. 1st (DN) or 2nd (filter) argument to
|
||||
* `search` method from `DirContext`.
|
||||
*/
|
||||
private class JndiLdapInjectionSink extends LdapInjectionSink {
|
||||
JndiLdapInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.asExpr() and
|
||||
jndiLdapInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate unboundIdLdapInjectionSinkMethod(Method m, int index) {
|
||||
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
|
||||
m instanceof MethodUnboundIdLDAPConnectionSearch or
|
||||
m instanceof MethodUnboundIdLDAPConnectionAsyncSearch or
|
||||
m instanceof MethodUnboundIdLDAPConnectionSearchForEntry
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* UnboundID sink for LDAP injection vulnerabilities,
|
||||
* i.e. LDAPConnection.search, LDAPConnection.asyncSearch or LDAPConnection.searchForEntry method.
|
||||
*/
|
||||
private class UnboundedIdLdapInjectionSink extends LdapInjectionSink {
|
||||
UnboundedIdLdapInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.asExpr() and
|
||||
unboundIdLdapInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate springLdapInjectionSinkMethod(Method m, int index) {
|
||||
// LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method
|
||||
(
|
||||
m instanceof MethodSpringLdapTemplateAuthenticate or
|
||||
m instanceof MethodSpringLdapTemplateFind or
|
||||
m instanceof MethodSpringLdapTemplateFindOne or
|
||||
m instanceof MethodSpringLdapTemplateSearch or
|
||||
m instanceof MethodSpringLdapTemplateSearchForContext or
|
||||
m instanceof MethodSpringLdapTemplateSearchForObject
|
||||
) and
|
||||
(
|
||||
// Parameter index is 1 (DN or query) or 2 (filter) if method is not authenticate
|
||||
index in [0 .. 1] and
|
||||
not m instanceof MethodSpringLdapTemplateAuthenticate
|
||||
or
|
||||
// But it's not the last parameter in case of authenticate method (last param is password)
|
||||
index in [0 .. 1] and
|
||||
index < m.getNumberOfParameters() - 1 and
|
||||
m instanceof MethodSpringLdapTemplateAuthenticate
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring LDAP sink for LDAP injection vulnerabilities,
|
||||
* i.e. LdapTemplate.authenticate, LdapTemplate.find* or LdapTemplate.search* method.
|
||||
*/
|
||||
private class SpringLdapInjectionSink extends LdapInjectionSink {
|
||||
SpringLdapInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.asExpr() and
|
||||
springLdapInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate apacheLdapInjectionSinkMethod(Method m, int index) {
|
||||
exists(Parameter param | m.getParameter(index) = param and not param.isVarargs() |
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeApacheLdapConnection and
|
||||
m.hasName("search")
|
||||
)
|
||||
}
|
||||
|
||||
/** Apache LDAP API sink for LDAP injection vulnerabilities, i.e. LdapConnection.search method. */
|
||||
private class ApacheLdapInjectionSink extends LdapInjectionSink {
|
||||
ApacheLdapInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.asExpr() and
|
||||
apacheLdapInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user