mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Refactored to use CSV sink models
This commit is contained in:
@@ -12,9 +12,28 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import JndiInjectionLib
|
||||
import semmle.code.java.security.JndiInjection
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in JNDI lookup.
|
||||
*/
|
||||
class JndiInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(JndiInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(),
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.Jndi
|
||||
import DataFlow
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in JNDI lookup.
|
||||
*/
|
||||
class JndiInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
nameStep(node1, node2) or
|
||||
jmxServiceUrlStep(node1, node2) or
|
||||
jmxConnectorStep(node1, node2) or
|
||||
rmiConnectorStep(node1, node2)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
import java
|
||||
|
||||
/** The class `javax.naming.InitialContext`. */
|
||||
class TypeInitialContext extends Class {
|
||||
TypeInitialContext() { this.hasQualifiedName("javax.naming", "InitialContext") }
|
||||
}
|
||||
|
||||
/** The class `javax.naming.CompositeName`. */
|
||||
class TypeCompositeName extends Class {
|
||||
TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") }
|
||||
@@ -14,3 +9,25 @@ class TypeCompositeName extends Class {
|
||||
class TypeCompoundName extends Class {
|
||||
TypeCompoundName() { this.hasQualifiedName("javax.naming", "CompoundName") }
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.rmi.RMIConnector`. */
|
||||
class TypeRMIConnector extends Class {
|
||||
TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") }
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.JMXConnectorFactory`. */
|
||||
class TypeJMXConnectorFactory extends Class {
|
||||
TypeJMXConnectorFactory() {
|
||||
this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory")
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.JMXServiceURL`. */
|
||||
class TypeJMXServiceURL extends Class {
|
||||
TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") }
|
||||
}
|
||||
|
||||
/** The interface `javax.naming.Context`. */
|
||||
class TypeNamingContext extends Interface {
|
||||
TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") }
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import java
|
||||
|
||||
/** The class `org.apache.shiro.jndi.JndiTemplate`. */
|
||||
class TypeShiroJndiTemplate extends Class {
|
||||
TypeShiroJndiTemplate() { this.hasQualifiedName("org.apache.shiro.jndi", "JndiTemplate") }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import java
|
||||
|
||||
/** The class `org.springframework.jndi.JndiTemplate`. */
|
||||
class TypeSpringJndiTemplate extends Class {
|
||||
TypeSpringJndiTemplate() { this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") }
|
||||
}
|
||||
@@ -82,6 +82,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.security.XSS
|
||||
private import semmle.code.java.security.LdapInjection
|
||||
private import semmle.code.java.security.XPath
|
||||
private import semmle.code.java.security.JndiInjection
|
||||
}
|
||||
|
||||
private predicate sourceModelCsv(string row) {
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow
|
||||
import experimental.semmle.code.java.frameworks.Jndi
|
||||
import experimental.semmle.code.java.frameworks.spring.SpringJndi
|
||||
import semmle.code.java.frameworks.SpringLdap
|
||||
import experimental.semmle.code.java.frameworks.Shiro
|
||||
|
||||
/** The class `java.util.Hashtable`. */
|
||||
class TypeHashtable extends Class {
|
||||
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
|
||||
}
|
||||
|
||||
/** The class `javax.naming.directory.SearchControls`. */
|
||||
class TypeSearchControls extends Class {
|
||||
TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface `org.springframework.ldap.core.LdapOperations` (spring-ldap 1.2.x and newer) or
|
||||
* `org.springframework.ldap.LdapOperations` (spring-ldap 1.1.x).
|
||||
*/
|
||||
class TypeSpringLdapOperations extends Interface {
|
||||
TypeSpringLdapOperations() {
|
||||
this.hasQualifiedName("org.springframework.ldap.core", "LdapOperations") or
|
||||
this.hasQualifiedName("org.springframework.ldap", "LdapOperations")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface `org.springframework.ldap.core.ContextMapper` (spring-ldap 1.2.x and newer) or
|
||||
* `org.springframework.ldap.ContextMapper` (spring-ldap 1.1.x).
|
||||
*/
|
||||
class TypeSpringContextMapper extends Interface {
|
||||
TypeSpringContextMapper() {
|
||||
this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or
|
||||
this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap", "ContextMapper")
|
||||
}
|
||||
}
|
||||
|
||||
/** The interface `javax.management.remote.JMXConnector`. */
|
||||
class TypeJMXConnector extends Interface {
|
||||
TypeJMXConnector() { this.hasQualifiedName("javax.management.remote", "JMXConnector") }
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.rmi.RMIConnector`. */
|
||||
class TypeRMIConnector extends Class {
|
||||
TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") }
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.JMXConnectorFactory`. */
|
||||
class TypeJMXConnectorFactory extends Class {
|
||||
TypeJMXConnectorFactory() {
|
||||
this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory")
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `javax.management.remote.JMXServiceURL`. */
|
||||
class TypeJMXServiceURL extends Class {
|
||||
TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") }
|
||||
}
|
||||
|
||||
/** The interface `javax.naming.Context`. */
|
||||
class TypeNamingContext extends Interface {
|
||||
TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") }
|
||||
}
|
||||
|
||||
/**
|
||||
* JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`,
|
||||
* `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`.
|
||||
*/
|
||||
predicate jndiSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeInitialContext and
|
||||
(
|
||||
m.hasName("lookup") or
|
||||
m.hasName("lookupLink") or
|
||||
m.hasName("doLookup") or
|
||||
m.hasName("rename") or
|
||||
m.hasName("list") or
|
||||
m.hasName("listBindings")
|
||||
) and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
|
||||
* Spring's `JndiTemplate`.
|
||||
*/
|
||||
predicate springJndiTemplateSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType() instanceof TypeSpringJndiTemplate and
|
||||
m.hasName("lookup") and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupContext`,
|
||||
* `findByDn`, `rename`, `list`, `listBindings`, `unbind`, `search` or `searchForObject` method
|
||||
* from Spring's `LdapOperations`.
|
||||
*/
|
||||
predicate springLdapTemplateSinkMethod(MethodAccess ma, Method m, int index) {
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeSpringLdapOperations and
|
||||
(
|
||||
m.hasName("lookup")
|
||||
or
|
||||
m.hasName("lookupContext")
|
||||
or
|
||||
m.hasName("findByDn")
|
||||
or
|
||||
m.hasName("rename")
|
||||
or
|
||||
m.hasName("list")
|
||||
or
|
||||
m.hasName("listBindings")
|
||||
or
|
||||
m.hasName("unbind") and ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
or
|
||||
m.getName().matches("search%") and
|
||||
m.getParameterType(m.getNumberOfParameters() - 1) instanceof TypeSpringContextMapper and
|
||||
not m.getAParamType() instanceof TypeSearchControls
|
||||
or
|
||||
m.hasName("search") and ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
) and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
|
||||
* Shiro's `JndiTemplate`.
|
||||
*/
|
||||
predicate shiroSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType() instanceof TypeShiroJndiTemplate and
|
||||
m.hasName("lookup") and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* `JMXConnectorFactory` sink for JNDI injection vulnerabilities, i.e. 1st argument to `connect`
|
||||
* method from `JMXConnectorFactory`.
|
||||
*/
|
||||
predicate jmxConnectorFactorySinkMethod(Method m, int index) {
|
||||
m.getDeclaringType() instanceof TypeJMXConnectorFactory and
|
||||
m.hasName("connect") and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Tainted value passed to env `Hashtable` as the provider URL, i.e.
|
||||
* `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`.
|
||||
*/
|
||||
predicate providerUrlEnv(MethodAccess ma, Method m, int index) {
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
(m.hasName("put") or m.hasName("setProperty")) and
|
||||
(
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"
|
||||
or
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName("PROVIDER_URL") and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
)
|
||||
) and
|
||||
index = 1
|
||||
}
|
||||
|
||||
/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */
|
||||
predicate jndiInjectionSinkMethod(MethodAccess ma, Method m, int index) {
|
||||
jndiSinkMethod(m, index) or
|
||||
springJndiTemplateSinkMethod(m, index) or
|
||||
springLdapTemplateSinkMethod(ma, m, index) or
|
||||
shiroSinkMethod(m, index) or
|
||||
jmxConnectorFactorySinkMethod(m, index) or
|
||||
providerUrlEnv(ma, m, index)
|
||||
}
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used in JNDI lookup. */
|
||||
class JndiInjectionSink extends DataFlow::ExprNode {
|
||||
JndiInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(index) = this.getExpr() and
|
||||
jndiInjectionSinkMethod(ma, m, index)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma, Method m |
|
||||
ma.getMethod() = m and
|
||||
ma.getQualifier() = this.getExpr() and
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and
|
||||
m.hasName("connect")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName` or
|
||||
* `CompoundName`, i.e. `new CompositeName(tainted)` or `new CompoundName(tainted)`.
|
||||
*/
|
||||
predicate nameStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType() instanceof TypeCompositeName or
|
||||
cc.getConstructedType() instanceof TypeCompoundName
|
||||
|
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`,
|
||||
* i.e. `new JMXServiceURL(tainted)`.
|
||||
*/
|
||||
predicate jmxServiceUrlStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeJMXServiceURL |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
|
||||
* `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`.
|
||||
*/
|
||||
predicate jmxConnectorStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getArgument(0) and n2.asExpr() = ma |
|
||||
ma.getMethod() = m and
|
||||
m.getDeclaringType() instanceof TypeJMXConnectorFactory and
|
||||
m.hasName("newJMXConnector")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
|
||||
* `RMIConnector`, i.e. `new RMIConnector(tainted)`.
|
||||
*/
|
||||
predicate rmiConnectorStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeRMIConnector |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
193
java/ql/src/semmle/code/java/security/JndiInjection.qll
Normal file
193
java/ql/src/semmle/code/java/security/JndiInjection.qll
Normal file
@@ -0,0 +1,193 @@
|
||||
/** Provides classes to reason about JNDI injection vulnerabilities. */
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import experimental.semmle.code.java.frameworks.Jndi
|
||||
import semmle.code.java.frameworks.SpringLdap
|
||||
import DataFlow
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used in JNDI lookup. */
|
||||
abstract class JndiInjectionSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
*
|
||||
* Extend this class to add additional taint steps that should apply to
|
||||
* the `JndiInjectionFlowConfig` configuration.
|
||||
*/
|
||||
class JndiInjectionAdditionalTaintStep extends Unit {
|
||||
/**
|
||||
* Holds if the step from `node1` to `node2` should be considered a taint
|
||||
* step for the `JndiInjectionFlowConfig` configuration.
|
||||
*/
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
/** A default sink representing methods susceptible to JNDI injection attacks. */
|
||||
private class DefaultJndiInjectionSink extends JndiInjectionSink {
|
||||
DefaultJndiInjectionSink() { sinkNode(this, "jndi-injection") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that does a JNDI lookup but needs a specific parameter set to `true` to be vulnerable
|
||||
*/
|
||||
private class ConditionedJndiInjectionSink extends JndiInjectionSink, DataFlow::ExprNode {
|
||||
ConditionedJndiInjectionSink() {
|
||||
exists(MethodAccess ma, Method m |
|
||||
ma.getMethod() = m and
|
||||
ma.getAnArgument() = this.asExpr() and
|
||||
m.getSourceDeclaration()
|
||||
.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName(["org.springframework.ldap.core", "org.springframework.ldap"],
|
||||
"LdapOperations")
|
||||
|
|
||||
m.hasName("search") and
|
||||
ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
or
|
||||
m.hasName("unbind") and
|
||||
ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tainted value passed to env `Hashtable` as the provider URL, i.e.
|
||||
* `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`.
|
||||
*/
|
||||
private class ProviderUrlJndiInjectionSink extends JndiInjectionSink, DataFlow::ExprNode {
|
||||
ProviderUrlJndiInjectionSink() {
|
||||
exists(MethodAccess ma, Method m |
|
||||
ma.getMethod() = m and
|
||||
ma.getArgument(1) = this.getExpr()
|
||||
|
|
||||
m.getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
(m.hasName("put") or m.hasName("setProperty")) and
|
||||
(
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"
|
||||
or
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName("PROVIDER_URL") and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** CSV sink models representing methods susceptible to JNDI injection attacks. */
|
||||
private class DefaultJndiInjectionSinkModel extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
// JDK
|
||||
"javax.naming;InitialContext;true;lookup;;;Argument[0];jndi-injection",
|
||||
"javax.naming;InitialContext;true;lookupLink;;;Argument[0];jndi-injection",
|
||||
"javax.naming;InitialContext;true;doLookup;;;Argument[0];jndi-injection",
|
||||
"javax.naming;InitialContext;true;rename;;;Argument[0];jndi-injection",
|
||||
"javax.naming;InitialContext;true;list;;;Argument[0];jndi-injection",
|
||||
"javax.naming;InitialContext;true;listBindings;;;Argument[0];jndi-injection",
|
||||
"javax.management.remote;JMXConnector;true;connect;;;Argument[-1];jndi-injection",
|
||||
"javax.management.remote;JMXConnectorFactory;false;connect;;;Argument[0];jndi-injection",
|
||||
// Spring
|
||||
"org.springframework.jndi;JndiTemplate;false;lookup;;;Argument[0];jndi-injection",
|
||||
// spring-ldap 1.2.x and newer
|
||||
"org.springframework.ldap.core;LdapOperations;true;lookup;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;lookupContext;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;findByDn;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;rename;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;list;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;listBindings;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(Name,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(Name,String,int,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(Name,String,int,String[],ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,int,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,int,String[],ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;searchForObject;(Name,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap.core;LdapOperations;true;searchForObject;(String,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
// spring-ldap 1.1.x
|
||||
"org.springframework.ldap;LdapOperations;true;lookup;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;lookupContext;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;findByDn;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;rename;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;list;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;listBindings;;;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(Name,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(Name,String,int,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(Name,String,int,String[],ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(String,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(String,String,int,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;search;(String,String,int,String[],ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;searchForObject;(Name,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
"org.springframework.ldap;LdapOperations;true;searchForObject;(String,String,ContextMapper<T>);;Argument[0];jndi-injection",
|
||||
// Shiro
|
||||
"org.apache.shiro.jndi;JndiTemplate;false;lookup;;;Argument[0];jndi-injection"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** A set of additional taint steps to consider when taint tracking JNDI injection related data flows. */
|
||||
private class DefaultJndiInjectionAdditionalTaintStep extends JndiInjectionAdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
nameStep(node1, node2) or
|
||||
jmxServiceUrlStep(node1, node2) or
|
||||
jmxConnectorStep(node1, node2) or
|
||||
rmiConnectorStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName` or
|
||||
* `CompoundName`, i.e. `new CompositeName(tainted)` or `new CompoundName(tainted)`.
|
||||
*/
|
||||
private predicate nameStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType() instanceof TypeCompositeName or
|
||||
cc.getConstructedType() instanceof TypeCompoundName
|
||||
|
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`,
|
||||
* i.e. `new JMXServiceURL(tainted)`.
|
||||
*/
|
||||
private predicate jmxServiceUrlStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeJMXServiceURL |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
|
||||
* `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`.
|
||||
*/
|
||||
private predicate jmxConnectorStep(ExprNode n1, ExprNode n2) {
|
||||
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getArgument(0) and n2.asExpr() = ma |
|
||||
ma.getMethod() = m and
|
||||
m.getDeclaringType() instanceof TypeJMXConnectorFactory and
|
||||
m.hasName("newJMXConnector")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
|
||||
* `RMIConnector`, i.e. `new RMIConnector(tainted)`.
|
||||
*/
|
||||
private predicate rmiConnectorStep(ExprNode n1, ExprNode n2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeRMIConnector |
|
||||
n1.asExpr() = cc.getAnArgument() and
|
||||
n2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/** The class `java.util.Hashtable`. */
|
||||
private class TypeHashtable extends Class {
|
||||
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
|
||||
}
|
||||
Reference in New Issue
Block a user