Merge pull request #5931 from atorralba/atorralba/promote-jndi-injection

Java: Promote JNDI Injection query from experimental
This commit is contained in:
Anders Schack-Mulligen
2021-08-04 15:48:44 +02:00
committed by GitHub
25 changed files with 725 additions and 691 deletions

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The query "JNDI lookup with user-controlled name" (`java/jndi-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @ggolawski](https://github.com/github/codeql/pull/3288).

View File

@@ -11,7 +11,7 @@ code execution.</p>
</overview>
<recommendation>
<p>The general recommendation is to not pass untrusted data to the <code>InitialContext.lookup
<p>The general recommendation is to avoid passing untrusted data to the <code>InitialContext.lookup
</code> method. If the name being used to look up the object must be provided by the user, make
sure that it's not in the form of an absolute URL or that it's the URL pointing to a trused server.
</p>

View File

@@ -1,6 +1,6 @@
/**
* @name JNDI lookup with user-controlled name
* @description Doing a JNDI lookup with user-controlled name can lead to download an untrusted
* @description Performing a JNDI lookup with a user-controlled name can lead to the download of an untrusted
* object and to execution of arbitrary code.
* @kind path-problem
* @problem.severity error
@@ -11,8 +11,7 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
import JndiInjectionLib
import semmle.code.java.security.JndiInjectionQuery
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf

View File

@@ -1,261 +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
/**
* 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)
}
}
/** 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
)
}

View File

@@ -30,11 +30,6 @@ class InsecureLdapUrlLiteral extends StringLiteral {
}
}
/** The interface `javax.naming.Context`. */
class TypeNamingContext extends Interface {
TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") }
}
/** The class `java.util.Hashtable`. */
class TypeHashtable extends Class {
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }

View File

@@ -1,16 +0,0 @@
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") }
}
/** The class `javax.naming.CompoundName`. */
class TypeCompoundName extends Class {
TypeCompoundName() { this.hasQualifiedName("javax.naming", "CompoundName") }
}

View File

@@ -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") }
}

View File

@@ -1,6 +0,0 @@
import java
/** The class `org.springframework.jndi.JndiTemplate`. */
class TypeSpringJndiTemplate extends Class {
TypeSpringJndiTemplate() { this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") }
}

View File

@@ -86,3 +86,20 @@ class JMXRegistrationMethod extends Method {
)
}
}
/** 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 class `javax.management.remote.rmi.RMIConnector`. */
class TypeRMIConnector extends Class {
TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") }
}

View File

@@ -99,6 +99,7 @@ private module Frameworks {
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.GroovyInjection
private import semmle.code.java.security.JexlInjectionSinkModels
private import semmle.code.java.security.JndiInjection
private import semmle.code.java.security.LdapInjection
private import semmle.code.java.security.MvelInjection
private import semmle.code.java.security.OgnlInjection

View File

@@ -1,5 +1,5 @@
/**
* Provides classes and predicates for working with the Java JDBC API.
* Provides classes and predicates for working with the Java JNDI API.
*/
import java
@@ -7,11 +7,31 @@ import semmle.code.java.Type
import semmle.code.java.Member
/*--- Types ---*/
/** The interface `javax.naming.Context`. */
class TypeNamingContext extends Interface {
TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") }
}
/** The class `javax.naming.CompositeName`. */
class TypeCompositeName extends Class {
TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") }
}
/** The class `javax.naming.CompoundName`. */
class TypeCompoundName extends Class {
TypeCompoundName() { this.hasQualifiedName("javax.naming", "CompoundName") }
}
/** The interface `javax.naming.directory.DirContext`. */
class TypeDirContext extends Interface {
TypeDirContext() { this.hasQualifiedName("javax.naming.directory", "DirContext") }
}
/** The class `javax.naming.directory.SearchControls` */
class TypeSearchControls extends Class {
TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") }
}
/** The class `javax.naming.ldap.LdapName`. */
class TypeLdapName extends Class {
TypeLdapName() { this.hasQualifiedName("javax.naming.ldap", "LdapName") }

View File

@@ -59,6 +59,17 @@ class TypeSpringLdapUtils extends Class {
TypeSpringLdapUtils() { this.hasQualifiedName("org.springframework.ldap.support", "LdapUtils") }
}
/**
* The interface `org.springframework.ldap.core.LdapOperations` or
* `org.springframework.ldap.LdapOperations`
*/
class TypeLdapOperations extends Interface {
TypeLdapOperations() {
this.hasQualifiedName(["org.springframework.ldap.core", "org.springframework.ldap"],
"LdapOperations")
}
}
/*--- Methods ---*/
/**
* A method with the name `authenticate` declared in

View File

@@ -0,0 +1,206 @@
/** Provides classes to reason about JNDI injection vulnerabilities. */
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.frameworks.Jndi
private import semmle.code.java.frameworks.SpringLdap
/** 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 when it receives a specific argument set to `true`.
*/
private class ConditionedJndiInjectionSink extends JndiInjectionSink, DataFlow::ExprNode {
ConditionedJndiInjectionSink() {
exists(MethodAccess ma, Method m |
ma.getMethod() = m and
ma.getArgument(0) = this.asExpr() and
m.getDeclaringType().getASourceSupertype*() instanceof TypeLdapOperations
|
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 by calling
* `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().getASourceSupertype*() 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 =
[
"javax.naming;Context;true;lookup;;;Argument[0];jndi-injection",
"javax.naming;Context;true;lookupLink;;;Argument[0];jndi-injection",
"javax.naming;Context;true;rename;;;Argument[0];jndi-injection",
"javax.naming;Context;true;list;;;Argument[0];jndi-injection",
"javax.naming;Context;true;listBindings;;;Argument[0];jndi-injection",
"javax.naming;InitialContext;true;doLookup;;;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);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;search;(Name,String,int,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;search;(Name,String,int,String[],ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,int,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;search;(String,String,int,String[],ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;searchForObject;(Name,String,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap.core;LdapOperations;true;searchForObject;(String,String,ContextMapper);;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);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;search;(Name,String,int,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;search;(Name,String,int,String[],ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;search;(String,String,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;search;(String,String,int,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;search;(String,String,int,String[],ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;searchForObject;(Name,String,ContextMapper);;Argument[0];jndi-injection",
"org.springframework.ldap;LdapOperations;true;searchForObject;(String,String,ContextMapper);;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
nameAddStep(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` by calling `new CompositeName(tainted)` or `new CompoundName(tainted)`.
*/
private predicate nameStep(DataFlow::ExprNode n1, DataFlow::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 `CompositeName` or
* `CompoundName` by calling `new CompositeName().add(tainted)` or `new CompoundName().add(tainted)`.
*/
private predicate nameAddStep(DataFlow::ExprNode n1, DataFlow::ExprNode n2) {
exists(Method m, MethodAccess ma |
ma.getMethod() = m and
m.hasName("add") and
(
m.getDeclaringType() instanceof TypeCompositeName or
m.getDeclaringType() instanceof TypeCompoundName
)
|
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`
* by calling `new JMXServiceURL(tainted)`.
*/
private predicate jmxServiceUrlStep(DataFlow::ExprNode n1, DataFlow::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` by calling `JMXConnectorFactory.newJMXConnector(tainted)`.
*/
private predicate jmxConnectorStep(DataFlow::ExprNode n1, DataFlow::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` by calling `new RMIConnector(tainted)`.
*/
private predicate rmiConnectorStep(DataFlow::ExprNode n1, DataFlow::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") }
}

View File

@@ -0,0 +1,97 @@
/** Provides taint tracking configurations to be used in JNDI injection queries. */
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.Jndi
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.security.JndiInjection
/**
* 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)
}
}
/**
* A method that does a JNDI lookup when it receives a `SearchControls` argument with `setReturningObjFlag` = `true`
*/
private class UnsafeSearchControlsSink extends JndiInjectionSink {
UnsafeSearchControlsSink() {
exists(UnsafeSearchControlsConf conf, MethodAccess ma |
conf.hasFlowTo(DataFlow::exprNode(ma.getAnArgument()))
|
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* Find flows between a `SearchControls` object with `setReturningObjFlag` = `true`
* and an argument of an `LdapOperations.search` or `DirContext.search` call.
*/
private class UnsafeSearchControlsConf extends DataFlow2::Configuration {
UnsafeSearchControlsConf() { this = "UnsafeSearchControlsConf" }
override predicate isSource(DataFlow::Node source) { source instanceof UnsafeSearchControls }
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeSearchControlsArgument }
}
/**
* An argument of type `SearchControls` of an `LdapOperations.search` or `DirContext.search` call.
*/
private class UnsafeSearchControlsArgument extends DataFlow::ExprNode {
UnsafeSearchControlsArgument() {
exists(MethodAccess ma, Method m |
ma.getMethod() = m and
ma.getAnArgument() = this.asExpr() and
this.asExpr().getType() instanceof TypeSearchControls and
m.hasName("search")
|
m.getDeclaringType().getASourceSupertype*() instanceof TypeLdapOperations or
m.getDeclaringType().getASourceSupertype*() instanceof TypeDirContext
)
}
}
/**
* A `SearchControls` object with `setReturningObjFlag` = `true`.
*/
private class UnsafeSearchControls extends DataFlow::ExprNode {
UnsafeSearchControls() {
exists(MethodAccess ma |
ma.getMethod() instanceof SetReturningObjFlagMethod and
ma.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true and
this.asExpr() = ma.getQualifier()
)
or
exists(ConstructorCall cc |
cc.getConstructedType() instanceof TypeSearchControls and
cc.getArgument(4).(CompileTimeConstantExpr).getBooleanValue() = true and
this.asExpr() = cc
)
}
}
/**
* The method `SearchControls.setReturningObjFlag`.
*/
private class SetReturningObjFlagMethod extends Method {
SetReturningObjFlagMethod() {
this.getDeclaringType() instanceof TypeSearchControls and
this.hasName("setReturningObjFlag")
}
}

View File

@@ -1,180 +0,0 @@
edges
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name |
| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name |
| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr |
| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr |
| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr |
| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr |
| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) |
| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector |
| JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr |
| JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr |
| JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr |
| JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr |
| JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr |
nodes
| JndiInjection.java:30:38:30:65 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:34:16:34:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:35:20:35:26 | nameStr | semmle.label | nameStr |
| JndiInjection.java:36:29:36:35 | nameStr | semmle.label | nameStr |
| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr |
| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr |
| JndiInjection.java:41:16:41:19 | name | semmle.label | name |
| JndiInjection.java:42:20:42:23 | name | semmle.label | name |
| JndiInjection.java:43:29:43:32 | name | semmle.label | name |
| JndiInjection.java:44:16:44:19 | name | semmle.label | name |
| JndiInjection.java:45:14:45:17 | name | semmle.label | name |
| JndiInjection.java:46:22:46:25 | name | semmle.label | name |
| JndiInjection.java:50:41:50:68 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:55:20:55:26 | nameStr | semmle.label | nameStr |
| JndiInjection.java:56:16:56:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:57:14:57:20 | nameStr | semmle.label | nameStr |
| JndiInjection.java:58:22:58:28 | nameStr | semmle.label | nameStr |
| JndiInjection.java:60:16:60:19 | name | semmle.label | name |
| JndiInjection.java:61:20:61:23 | name | semmle.label | name |
| JndiInjection.java:62:16:62:19 | name | semmle.label | name |
| JndiInjection.java:63:14:63:17 | name | semmle.label | name |
| JndiInjection.java:64:22:64:25 | name | semmle.label | name |
| JndiInjection.java:68:42:68:69 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:72:16:72:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:73:20:73:26 | nameStr | semmle.label | nameStr |
| JndiInjection.java:74:16:74:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:75:14:75:20 | nameStr | semmle.label | nameStr |
| JndiInjection.java:76:22:76:28 | nameStr | semmle.label | nameStr |
| JndiInjection.java:78:16:78:19 | name | semmle.label | name |
| JndiInjection.java:79:20:79:23 | name | semmle.label | name |
| JndiInjection.java:80:16:80:19 | name | semmle.label | name |
| JndiInjection.java:81:14:81:17 | name | semmle.label | name |
| JndiInjection.java:82:22:82:25 | name | semmle.label | name |
| JndiInjection.java:86:42:86:69 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:89:16:89:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:90:16:90:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:94:42:94:69 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:98:16:98:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:99:23:99:29 | nameStr | semmle.label | nameStr |
| JndiInjection.java:100:18:100:21 | name | semmle.label | name |
| JndiInjection.java:101:16:101:19 | name | semmle.label | name |
| JndiInjection.java:102:14:102:17 | name | semmle.label | name |
| JndiInjection.java:103:22:103:25 | name | semmle.label | name |
| JndiInjection.java:104:16:104:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:106:16:106:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:107:16:107:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:108:16:108:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:109:16:109:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:111:25:111:31 | nameStr | semmle.label | nameStr |
| JndiInjection.java:115:41:115:68 | nameStr : String | semmle.label | nameStr : String |
| JndiInjection.java:118:16:118:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:119:16:119:22 | nameStr | semmle.label | nameStr |
| JndiInjection.java:123:37:123:63 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) |
| JndiInjection.java:128:5:128:13 | connector | semmle.label | connector |
| JndiInjection.java:132:27:132:53 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:135:35:135:40 | urlStr | semmle.label | urlStr |
| JndiInjection.java:140:27:140:53 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:143:41:143:46 | urlStr | semmle.label | urlStr |
| JndiInjection.java:148:52:148:78 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:151:37:151:42 | urlStr | semmle.label | urlStr |
| JndiInjection.java:156:52:156:78 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:159:51:159:56 | urlStr | semmle.label | urlStr |
| JndiInjection.java:164:52:164:78 | urlStr : String | semmle.label | urlStr : String |
| JndiInjection.java:167:51:167:56 | urlStr | semmle.label | urlStr |
#select
| JndiInjection.java:34:16:34:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:35:20:35:26 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:36:29:36:35 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:43:29:43:32 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:44:16:44:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:45:14:45:17 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:46:22:46:25 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input |
| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:55:20:55:26 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:56:16:56:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:57:14:57:20 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:58:22:58:28 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:61:20:61:23 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:62:16:62:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:63:14:63:17 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:64:22:64:25 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input |
| JndiInjection.java:72:16:72:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:73:20:73:26 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:74:16:74:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:75:14:75:20 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:76:22:76:28 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:78:16:78:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:79:20:79:23 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:80:16:80:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:81:14:81:17 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:82:22:82:25 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input |
| JndiInjection.java:89:16:89:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input |
| JndiInjection.java:90:16:90:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input |
| JndiInjection.java:98:16:98:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:99:23:99:29 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:100:18:100:21 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:101:16:101:19 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:102:14:102:17 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:103:22:103:25 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:104:16:104:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:106:16:106:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:107:16:107:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:108:16:108:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:111:25:111:31 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input |
| JndiInjection.java:118:16:118:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input |
| JndiInjection.java:119:16:119:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input |
| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input |
| JndiInjection.java:128:5:128:13 | connector | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input |
| JndiInjection.java:135:35:135:40 | urlStr | JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:132:27:132:53 | urlStr | this user input |
| JndiInjection.java:143:41:143:46 | urlStr | JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:140:27:140:53 | urlStr | this user input |
| JndiInjection.java:151:37:151:42 | urlStr | JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:148:52:148:78 | urlStr | this user input |
| JndiInjection.java:159:51:159:56 | urlStr | JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:156:52:156:78 | urlStr | this user input |
| JndiInjection.java:167:51:167:56 | urlStr | JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:164:52:164:78 | urlStr | this user input |

View File

@@ -1,209 +0,0 @@
import java.io.IOException;
import java.util.Hashtable;
import java.util.Properties;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.CompositeName;
import javax.naming.CompoundName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.ldap.InitialLdapContext;
import org.springframework.jndi.JndiTemplate;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.NameClassPairCallbackHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JndiInjection {
@RequestMapping
public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompositeName(nameStr);
InitialContext ctx = new InitialContext();
ctx.lookup(nameStr);
ctx.lookupLink(nameStr);
InitialContext.doLookup(nameStr);
ctx.rename(nameStr, "");
ctx.list(nameStr);
ctx.listBindings(nameStr);
ctx.lookup(name);
ctx.lookupLink(name);
InitialContext.doLookup(name);
ctx.rename(name, null);
ctx.list(name);
ctx.listBindings(name);
}
@RequestMapping
public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompoundName(nameStr, new Properties());
InitialDirContext ctx = new InitialDirContext();
ctx.lookup(nameStr);
ctx.lookupLink(nameStr);
ctx.rename(nameStr, "");
ctx.list(nameStr);
ctx.listBindings(nameStr);
ctx.lookup(name);
ctx.lookupLink(name);
ctx.rename(name, null);
ctx.list(name);
ctx.listBindings(name);
}
@RequestMapping
public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompositeName(nameStr);
InitialLdapContext ctx = new InitialLdapContext();
ctx.lookup(nameStr);
ctx.lookupLink(nameStr);
ctx.rename(nameStr, "");
ctx.list(nameStr);
ctx.listBindings(nameStr);
ctx.lookup(name);
ctx.lookupLink(name);
ctx.rename(name, null);
ctx.list(name);
ctx.listBindings(name);
}
@RequestMapping
public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException {
JndiTemplate ctx = new JndiTemplate();
ctx.lookup(nameStr);
ctx.lookup(nameStr, null);
}
@RequestMapping
public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException {
LdapTemplate ctx = new LdapTemplate();
Name name = new CompositeName(nameStr);
ctx.lookup(nameStr);
ctx.lookupContext(nameStr);
ctx.findByDn(name, null);
ctx.rename(name, null);
ctx.list(name);
ctx.listBindings(name);
ctx.unbind(nameStr, true);
ctx.search(nameStr, "", 0, true, null);
ctx.search(nameStr, "", 0, new String[] {}, (ContextMapper<Object>) new Object());
ctx.search(nameStr, "", 0, (ContextMapper<Object>) new Object());
ctx.search(nameStr, "", (ContextMapper) new Object());
ctx.searchForObject(nameStr, "", (ContextMapper) new Object());
}
@RequestMapping
public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException {
org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate();
ctx.lookup(nameStr);
ctx.lookup(nameStr, null);
}
@RequestMapping
public void testJMXServiceUrlBad1(@RequestParam String urlStr) throws IOException {
JMXConnectorFactory.connect(new JMXServiceURL(urlStr));
JMXServiceURL url = new JMXServiceURL(urlStr);
JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null);
connector.connect();
}
@RequestMapping
public void testEnvBad1(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL, urlStr);
new InitialContext(env);
}
@RequestMapping
public void testEnvBad2(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put("java.naming.provider.url", urlStr);
new InitialDirContext(env);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad1(@RequestParam String urlStr) throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
props.put(Context.PROVIDER_URL, urlStr);
new JndiTemplate(props);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad2(@RequestParam String urlStr) throws NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
props.setProperty("java.naming.provider.url", urlStr);
new JndiTemplate(props);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad3(@RequestParam String urlStr) throws NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
props.setProperty("java.naming.provider.url", urlStr);
JndiTemplate template = new JndiTemplate();
template.setEnvironment(props);
}
@RequestMapping
public void testSpringLdapTemplateOk1(@RequestParam String nameStr) throws NamingException {
LdapTemplate ctx = new LdapTemplate();
ctx.unbind(nameStr);
ctx.unbind(nameStr, false);
ctx.search(nameStr, "", 0, false, null);
ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object());
ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object(), null);
ctx.search(nameStr, "", (NameClassPairCallbackHandler) new Object());
ctx.search(nameStr, "", 0, new String[] {}, (AttributesMapper<Object>) new Object());
ctx.search(nameStr, "", 0, (AttributesMapper<Object>) new Object());
ctx.search(nameStr, "", (AttributesMapper) new Object());
ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object());
ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object());
ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object(), null);
ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object(), null);
ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object());
}
@RequestMapping
public void testEnvOk1(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.SECURITY_PRINCIPAL, urlStr);
new InitialContext(env);
}
@RequestMapping
public void testEnvOk2(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put("java.naming.security.principal", urlStr);
new InitialContext(env);
}
}

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-074/JndiInjection.ql

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../../stubs/spring-ldap-2.3.2

View File

@@ -0,0 +1,264 @@
import java.io.IOException;
import java.util.Hashtable;
import java.util.Properties;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.CompositeName;
import javax.naming.CompoundName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.ldap.InitialLdapContext;
import org.springframework.jndi.JndiTemplate;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextProcessor;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.NameClassPairCallbackHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JndiInjectionTest {
@RequestMapping
public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompositeName(nameStr);
InitialContext ctx = new InitialContext();
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookupLink(nameStr); // $hasJndiInjection
InitialContext.doLookup(nameStr); // $hasJndiInjection
ctx.rename(nameStr, ""); // $hasJndiInjection
ctx.list(nameStr); // $hasJndiInjection
ctx.listBindings(nameStr); // $hasJndiInjection
ctx.lookup(name); // $hasJndiInjection
ctx.lookupLink(name); // $hasJndiInjection
InitialContext.doLookup(name); // $hasJndiInjection
ctx.rename(name, null); // $hasJndiInjection
ctx.list(name); // $hasJndiInjection
ctx.listBindings(name); // $hasJndiInjection
}
@RequestMapping
public void testDirContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompoundName(nameStr, new Properties());
DirContext ctx = new InitialDirContext();
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookupLink(nameStr); // $hasJndiInjection
ctx.rename(nameStr, ""); // $hasJndiInjection
ctx.list(nameStr); // $hasJndiInjection
ctx.listBindings(nameStr); // $hasJndiInjection
ctx.lookup(name); // $hasJndiInjection
ctx.lookupLink(name); // $hasJndiInjection
ctx.rename(name, null); // $hasJndiInjection
ctx.list(name); // $hasJndiInjection
ctx.listBindings(name); // $hasJndiInjection
SearchControls searchControls = new SearchControls();
searchControls.setReturningObjFlag(true);
ctx.search(nameStr, "", searchControls); // $hasJndiInjection
ctx.search(nameStr, "", new Object[] {}, searchControls); // $hasJndiInjection
SearchControls searchControls2 = new SearchControls(1, 0, 0, null, true, false);
ctx.search(nameStr, "", searchControls2); // $hasJndiInjection
ctx.search(nameStr, "", new Object[] {}, searchControls2); // $hasJndiInjection
SearchControls searchControls3 = new SearchControls(1, 0, 0, null, false, false);
ctx.search(nameStr, "", searchControls3); // Safe
ctx.search(nameStr, "", new Object[] {}, searchControls3); // Safe
}
@RequestMapping
public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException {
Name name = new CompositeName(nameStr);
InitialLdapContext ctx = new InitialLdapContext();
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookupLink(nameStr); // $hasJndiInjection
ctx.rename(nameStr, ""); // $hasJndiInjection
ctx.list(nameStr); // $hasJndiInjection
ctx.listBindings(nameStr); // $hasJndiInjection
ctx.lookup(name); // $hasJndiInjection
ctx.lookupLink(name); // $hasJndiInjection
ctx.rename(name, null); // $hasJndiInjection
ctx.list(name); // $hasJndiInjection
ctx.listBindings(name); // $hasJndiInjection
}
@RequestMapping
public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException {
JndiTemplate ctx = new JndiTemplate();
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookup(nameStr, null); // $hasJndiInjection
}
@RequestMapping
public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException {
LdapTemplate ctx = new LdapTemplate();
Name name = new CompositeName().add(nameStr);
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookupContext(nameStr); // $hasJndiInjection
ctx.findByDn(name, null); // $hasJndiInjection
ctx.rename(name, null); // $hasJndiInjection
ctx.list(name); // $hasJndiInjection
ctx.listBindings(name); // $hasJndiInjection
ctx.unbind(nameStr, true); // $hasJndiInjection
ctx.search(nameStr, "", 0, true, null); // $hasJndiInjection
ctx.search(nameStr, "", 0, new String[] {}, (ContextMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", 0, (ContextMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", (ContextMapper<Object>) null); // $hasJndiInjection
SearchControls searchControls = new SearchControls();
searchControls.setReturningObjFlag(true);
ctx.search(nameStr, "", searchControls, (AttributesMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls, (AttributesMapper<Object>) null, // $hasJndiInjection
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls, (ContextMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls, (ContextMapper<Object>) null, // $hasJndiInjection
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls, (NameClassPairCallbackHandler) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls, (NameClassPairCallbackHandler) null, // $hasJndiInjection
(DirContextProcessor) null);
SearchControls searchControls2 = new SearchControls(1, 0, 0, null, true, false);
ctx.search(nameStr, "", searchControls2, (AttributesMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls2, (AttributesMapper<Object>) null, // $hasJndiInjection
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls2, (ContextMapper<Object>) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls2, (ContextMapper<Object>) null, // $hasJndiInjection
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls2, (NameClassPairCallbackHandler) null); // $hasJndiInjection
ctx.search(nameStr, "", searchControls2, (NameClassPairCallbackHandler) null, // $hasJndiInjection
(DirContextProcessor) null);
SearchControls searchControls3 = new SearchControls(1, 0, 0, null, false, false);
ctx.search(nameStr, "", searchControls3, (AttributesMapper<Object>) null); // Safe
ctx.search(nameStr, "", searchControls3, (AttributesMapper<Object>) null, // Safe
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls3, (ContextMapper<Object>) null); // Safe
ctx.search(nameStr, "", searchControls3, (ContextMapper<Object>) null, // Safe
(DirContextProcessor) null);
ctx.search(nameStr, "", searchControls3, (NameClassPairCallbackHandler) null); // Safe
ctx.search(nameStr, "", searchControls3, (NameClassPairCallbackHandler) null, // Safe
(DirContextProcessor) null);
ctx.searchForObject(nameStr, "", (ContextMapper<Object>) null); // $hasJndiInjection
}
@RequestMapping
public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException {
org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate();
ctx.lookup(nameStr); // $hasJndiInjection
ctx.lookup(nameStr, null); // $hasJndiInjection
}
@RequestMapping
public void testJMXServiceUrlBad1(@RequestParam String urlStr) throws IOException {
JMXConnectorFactory.connect(new JMXServiceURL(urlStr)); // $hasJndiInjection
JMXServiceURL url = new JMXServiceURL(urlStr);
JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null);
connector.connect(); // $hasJndiInjection
}
@RequestMapping
public void testEnvBad1(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL, urlStr); // $hasJndiInjection
new InitialContext(env);
}
@RequestMapping
public void testEnvBad2(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put("java.naming.provider.url", urlStr); // $hasJndiInjection
new InitialDirContext(env);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad1(@RequestParam String urlStr)
throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
props.put(Context.PROVIDER_URL, urlStr); // $hasJndiInjection
new JndiTemplate(props);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad2(@RequestParam String urlStr)
throws NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
props.setProperty("java.naming.provider.url", urlStr); // $hasJndiInjection
new JndiTemplate(props);
}
@RequestMapping
public void testSpringJndiTemplatePropertiesBad3(@RequestParam String urlStr)
throws NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
props.setProperty("java.naming.provider.url", urlStr); // $hasJndiInjection
JndiTemplate template = new JndiTemplate();
template.setEnvironment(props);
}
@RequestMapping
public void testSpringLdapTemplateOk1(@RequestParam String nameStr) throws NamingException {
LdapTemplate ctx = new LdapTemplate();
ctx.unbind(nameStr); // Safe
ctx.unbind(nameStr, false); // Safe
ctx.search(nameStr, "", 0, false, null); // Safe
ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object()); // Safe
ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object(), // Safe
null);
ctx.search(nameStr, "", (NameClassPairCallbackHandler) new Object()); // Safe
ctx.search(nameStr, "", 0, new String[] {}, (AttributesMapper<Object>) new Object()); // Safe
ctx.search(nameStr, "", 0, (AttributesMapper<Object>) new Object()); // Safe
ctx.search(nameStr, "", (AttributesMapper) new Object()); // Safe
ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object()); // Safe
ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object()); // Safe
ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object(), null); // Safe
ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object(), null); // Safe
ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object()); // Safe
}
@RequestMapping
public void testEnvOk1(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.SECURITY_PRINCIPAL, urlStr); // Safe
new InitialContext(env);
}
@RequestMapping
public void testEnvOk2(@RequestParam String urlStr) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put("java.naming.security.principal", urlStr); // Safe
new InitialContext(env);
}
}

View File

@@ -0,0 +1,20 @@
import java
import semmle.code.java.security.JndiInjectionQuery
import TestUtilities.InlineExpectationsTest
class HasJndiInjectionTest extends InlineExpectationsTest {
HasJndiInjectionTest() { this = "HasJndiInjectionTest" }
override string getARelevantTag() { result = "hasJndiInjection" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasJndiInjection" and
exists(DataFlow::Node src, DataFlow::Node sink, JndiInjectionFlowConfig conf |
conf.hasFlow(src, sink)
|
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2

View File

@@ -1,3 +1,84 @@
package org.springframework.ldap.core;
public interface LdapOperations {}
import java.util.*;
import javax.naming.Name;
import javax.naming.directory.SearchControls;
import org.springframework.ldap.filter.Filter;
import org.springframework.ldap.query.LdapQuery;
public interface LdapOperations {
void authenticate(LdapQuery query, String password);
boolean authenticate(Name base, String filter, String password);
<T> List<T> find(Name base, Filter filter, SearchControls searchControls, final Class<T> clazz);
<T> List<T> find(LdapQuery query, Class<T> clazz);
<T> T findOne(LdapQuery query, Class<T> clazz);
void search(String base, String filter, int searchScope, boolean returningObjFlag,
NameClassPairCallbackHandler handler);
void search(final String base, final String filter, final SearchControls controls,
NameClassPairCallbackHandler handler);
void search(final String base, final String filter, final SearchControls controls,
NameClassPairCallbackHandler handler, DirContextProcessor processor);
void search(String base, String filter, NameClassPairCallbackHandler handler);
<T> List<T> search(String base, String filter, int searchScope, String[] attrs,
AttributesMapper<T> mapper);
<T> List<T> search(String base, String filter, int searchScope, AttributesMapper<T> mapper);
<T> List<T> search(String base, String filter, AttributesMapper<T> mapper);
<T> List<T> search(String base, String filter, int searchScope, String[] attrs,
ContextMapper<T> mapper);
<T> List<T> search(String base, String filter, int searchScope, ContextMapper<T> mapper);
<T> List<T> search(String base, String filter, ContextMapper<T> mapper);
<T> List<T> search(String base, String filter, SearchControls controls,
ContextMapper<T> mapper);
<T> List<T> search(String base, String filter, SearchControls controls,
AttributesMapper<T> mapper);
<T> List<T> search(String base, String filter, SearchControls controls,
AttributesMapper<T> mapper, DirContextProcessor processor);
<T> List<T> search(String base, String filter, SearchControls controls, ContextMapper<T> mapper,
DirContextProcessor processor);
DirContextOperations searchForContext(LdapQuery query);
<T> T searchForObject(Name base, String filter, ContextMapper<T> mapper);
<T> T searchForObject(String base, String filter, ContextMapper<T> mapper);
<T> T searchForObject(String base, String filter, SearchControls searchControls,
ContextMapper<T> mapper);
Object lookup(final String dn);
DirContextOperations lookupContext(String dn);
<T> T findByDn(Name dn, final Class<T> clazz);
void rename(final Name oldDn, final Name newDn);
List<String> list(final Name base);
List<String> listBindings(final Name base);
void unbind(final String dn);
void unbind(final String dn, boolean recursive);
}