@@ -3,6 +3,7 @@ import semmle.code.java.dataflow.FlowSources
33import DataFlow
44import experimental.semmle.code.java.frameworks.Jndi
55import experimental.semmle.code.java.frameworks.spring.SpringJndi
6+ import semmle.code.java.frameworks.SpringLdap
67import 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. */
65111predicate 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