Skip to content

Commit f893954

Browse files
committed
Add Spring LDAP and JMXServiceURL related sinks
1 parent 0c75330 commit f893954

File tree

18 files changed

+351
-117
lines changed

18 files changed

+351
-117
lines changed

java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import semmle.code.java.dataflow.FlowSources
33
import DataFlow
44
import experimental.semmle.code.java.frameworks.Jndi
55
import experimental.semmle.code.java.frameworks.spring.SpringJndi
6+
import semmle.code.java.frameworks.SpringLdap
67
import experimental.semmle.code.java.frameworks.Shiro
78

89
/**
@@ -20,10 +21,35 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration {
2021
}
2122

2223
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
23-
compositeNameStep(node1, node2)
24+
compositeNameStep(node1, node2) or
25+
jmxServiceUrlStep(node1, node2) or
26+
jmxConnectorStep(node1, node2) or
27+
rmiConnectorStep(node1, node2)
2428
}
2529
}
2630

31+
/** The interface `javax.management.remote.JMXConnector`. */
32+
class TypeJMXConnector extends Interface {
33+
TypeJMXConnector() { this.hasQualifiedName("javax.management.remote", "JMXConnector") }
34+
}
35+
36+
/** The class `javax.management.remote.rmi.RMIConnector`. */
37+
class TypeRMIConnector extends Class {
38+
TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") }
39+
}
40+
41+
/** The class `javax.management.remote.JMXConnectorFactory`. */
42+
class TypeJMXConnectorFactory extends Class {
43+
TypeJMXConnectorFactory() {
44+
this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory")
45+
}
46+
}
47+
48+
/** The class `javax.management.remote.JMXServiceURL`. */
49+
class TypeJMXServiceURL extends Class {
50+
TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") }
51+
}
52+
2753
/**
2854
* JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`,
2955
* `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`.
@@ -45,12 +71,22 @@ predicate jndiSinkMethod(Method m, int index) {
4571
* Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
4672
* Spring's `JndiTemplate`.
4773
*/
48-
predicate springSinkMethod(Method m, int index) {
74+
predicate springJndiTemplateSinkMethod(Method m, int index) {
4975
m.getDeclaringType() instanceof TypeSpringJndiTemplate and
5076
m.hasName("lookup") and
5177
index = 0
5278
}
5379

80+
/**
81+
* Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` or `lookupContext`
82+
* method from Spring's `LdapTemplate`.
83+
*/
84+
predicate springLdapTemplateSinkMethod(Method m, int index) {
85+
m.getDeclaringType() instanceof TypeSpringLdapTemplate and
86+
(m.hasName("lookup") or m.hasName("lookupContext")) and
87+
index = 0
88+
}
89+
5490
/**
5591
* Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from
5692
* Shiro's `JndiTemplate`.
@@ -61,11 +97,23 @@ predicate shiroSinkMethod(Method m, int index) {
6197
index = 0
6298
}
6399

100+
/**
101+
* `JMXConnectorFactory` sink for JNDI injection vulnerabilities, i.e. 1st argument to `connect`
102+
* method from `JMXConnectorFactory`.
103+
*/
104+
predicate jmxConnectorFactorySinkMethod(Method m, int index) {
105+
m.getDeclaringType() instanceof TypeJMXConnectorFactory and
106+
m.hasName("connect") and
107+
index = 0
108+
}
109+
64110
/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */
65111
predicate jndiInjectionSinkMethod(Method m, int index) {
66112
jndiSinkMethod(m, index) or
67-
springSinkMethod(m, index) or
68-
shiroSinkMethod(m, index)
113+
springJndiTemplateSinkMethod(m, index) or
114+
springLdapTemplateSinkMethod(m, index) or
115+
shiroSinkMethod(m, index) or
116+
jmxConnectorFactorySinkMethod(m, index)
69117
}
70118

71119
/** A data flow sink for unvalidated user input that is used in JNDI lookup. */
@@ -76,6 +124,13 @@ class JndiInjectionSink extends DataFlow::ExprNode {
76124
ma.getArgument(index) = this.getExpr() and
77125
jndiInjectionSinkMethod(m, index)
78126
)
127+
or
128+
exists(MethodAccess ma, Method m |
129+
ma.getMethod() = m and
130+
ma.getQualifier() = this.getExpr() and
131+
m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and
132+
m.hasName("connect")
133+
)
79134
}
80135
}
81136

@@ -89,3 +144,37 @@ predicate compositeNameStep(ExprNode n1, ExprNode n2) {
89144
n2.asExpr() = cc
90145
)
91146
}
147+
148+
/**
149+
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`,
150+
* i.e. `new JMXServiceURL(tainted)`.
151+
*/
152+
predicate jmxServiceUrlStep(ExprNode n1, ExprNode n2) {
153+
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeJMXServiceURL |
154+
n1.asExpr() = cc.getAnArgument() and
155+
n2.asExpr() = cc
156+
)
157+
}
158+
159+
/**
160+
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
161+
* `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`.
162+
*/
163+
predicate jmxConnectorStep(ExprNode n1, ExprNode n2) {
164+
exists(MethodAccess ma, Method m | n1.asExpr() = ma.getArgument(0) and n2.asExpr() = ma |
165+
ma.getMethod() = m and
166+
m.getDeclaringType() instanceof TypeJMXConnectorFactory and
167+
m.hasName("newJMXConnector")
168+
)
169+
}
170+
171+
/**
172+
* Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and
173+
* `RMIConnector`, i.e. `new RMIConnector(tainted)`.
174+
*/
175+
predicate rmiConnectorStep(ExprNode n1, ExprNode n2) {
176+
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeRMIConnector |
177+
n1.asExpr() = cc.getAnArgument() and
178+
n2.asExpr() = cc
179+
)
180+
}

0 commit comments

Comments
 (0)