Skip to content

Commit 2bb2baf

Browse files
committed
Support more methods that evaluate XPath expressions
1 parent 3705970 commit 2bb2baf

File tree

5 files changed

+185
-32
lines changed

5 files changed

+185
-32
lines changed

java/ql/src/semmle/code/java/security/XPath.qll

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ private class XPath extends RefType {
99
XPath() { this.hasQualifiedName("javax.xml.xpath", "XPath") }
1010
}
1111

12-
/** A call to `XPath.evaluate` or `XPath.compile` */
13-
private class XPathEvaluateOrCompile extends MethodAccess {
14-
XPathEvaluateOrCompile() {
12+
/** A call to methods of any class implementing the interface `XPath` that evaluate XPath expressions */
13+
private class XPathEvaluation extends MethodAccess {
14+
XPathEvaluation() {
1515
exists(Method m |
16-
this.getMethod() = m and m.getDeclaringType() instanceof XPath
16+
this.getMethod() = m and m.getDeclaringType().getASourceSupertype*() instanceof XPath
1717
|
18-
m.hasName(["evaluate", "compile"])
18+
m.hasName(["evaluate", "evaluateExpression", "compile"])
1919
)
2020
}
2121
}
@@ -25,13 +25,16 @@ private class Dom4JNode extends Interface {
2525
Dom4JNode() { this.hasQualifiedName("org.dom4j", "Node") }
2626
}
2727

28-
/** A call to `Node.selectNodes` or `Node.selectSingleNode` */
29-
private class NodeSelectNodes extends MethodAccess {
30-
NodeSelectNodes() {
28+
/** A call to methods of any class implementing the interface `Node` that evaluate XPath expressions */
29+
private class NodeXPathEvaluation extends MethodAccess {
30+
NodeXPathEvaluation() {
3131
exists(Method m |
3232
this.getMethod() = m and m.getDeclaringType().getASourceSupertype*() instanceof Dom4JNode
3333
|
34-
m.hasName(["selectNodes", "selectSingleNode"])
34+
m.hasName([
35+
"selectObject", "selectNodes", "selectSingleNode", "numberValueOf", "valueOf", "matches",
36+
"createXPath"
37+
])
3538
)
3639
}
3740
}
@@ -44,7 +47,7 @@ abstract class XPathInjectionSink extends DataFlow::Node { }
4447

4548
private class DefaultXPathInjectionSink extends XPathInjectionSink {
4649
DefaultXPathInjectionSink() {
47-
exists(NodeSelectNodes sink | sink.getArgument(0) = this.asExpr()) or
48-
exists(XPathEvaluateOrCompile sink | sink.getArgument(0) = this.asExpr())
50+
exists(NodeXPathEvaluation sink | sink.getArgument(0) = this.asExpr()) or
51+
exists(XPathEvaluation sink | sink.getArgument(0) = this.asExpr())
4952
}
5053
}

java/ql/test/experimental/query-tests/security/CWE-643/A.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,64 @@
22
import java.io.StringReader;
33

44
import javax.servlet.http.HttpServletRequest;
5+
import javax.xml.namespace.QName;
56
import javax.xml.parsers.DocumentBuilder;
67
import javax.xml.parsers.DocumentBuilderFactory;
78
import javax.xml.xpath.XPath;
89
import javax.xml.xpath.XPathConstants;
910
import javax.xml.xpath.XPathExpression;
11+
import javax.xml.xpath.XPathExpressionException;
1012
import javax.xml.xpath.XPathFactory;
1113

1214
import org.w3c.dom.Document;
1315
import org.xml.sax.InputSource;
1416

1517
public class A {
18+
private static abstract class XPathImplStub implements XPath {
19+
public static XPathImplStub getInstance() {
20+
return null;
21+
}
22+
23+
@Override
24+
public XPathExpression compile(String expression) throws XPathExpressionException {
25+
return null;
26+
}
27+
28+
@Override
29+
public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException {
30+
return null;
31+
}
32+
33+
@Override
34+
public String evaluate(String expression, Object item) throws XPathExpressionException {
35+
return null;
36+
}
37+
38+
@Override
39+
public Object evaluate(String expression, InputSource source, QName returnType)
40+
throws XPathExpressionException {
41+
return null;
42+
}
43+
44+
@Override
45+
public String evaluate(String expression, InputSource source) throws XPathExpressionException {
46+
return null;
47+
}
48+
49+
}
50+
1651
public void handle(HttpServletRequest request) throws Exception {
1752
final String xmlStr = "<users>" + " <user name=\"aaa\" pass=\"pass1\"></user>"
1853
+ " <user name=\"bbb\" pass=\"pass2\"></user>" + "</users>";
1954
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
2055
domFactory.setNamespaceAware(true);
2156
DocumentBuilder builder = domFactory.newDocumentBuilder();
22-
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
57+
InputSource xmlSource = new InputSource(new StringReader(xmlStr));
58+
Document doc = builder.parse(xmlSource);
2359

2460
XPathFactory factory = XPathFactory.newInstance();
2561
XPath xpath = factory.newXPath();
62+
XPathImplStub xpathStub = XPathImplStub.getInstance();
2663

2764
// Injectable data
2865
String user = request.getParameter("user");
@@ -31,9 +68,13 @@ public void handle(HttpServletRequest request) throws Exception {
3168
// Bad expression
3269
String expression1 = "/users/user[@name='" + user + "' and @pass='" + pass + "']";
3370
xpath.evaluate(expression1, doc, XPathConstants.BOOLEAN); // $hasXPathInjection
71+
xpathStub.evaluate(expression1, doc, XPathConstants.BOOLEAN); // $hasXPathInjection
72+
xpath.evaluateExpression(expression1, xmlSource); // $hasXPathInjection
73+
xpathStub.evaluateExpression(expression1, xmlSource); // $hasXPathInjection
3474

3575
// Bad expression
3676
XPathExpression expression2 = xpath.compile("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
77+
xpathStub.compile("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
3778
expression2.evaluate(doc, XPathConstants.BOOLEAN);
3879

3980
// Bad expression
@@ -44,6 +85,7 @@ public void handle(HttpServletRequest request) throws Exception {
4485
sb.append("']");
4586
String query = sb.toString();
4687
XPathExpression expression3 = xpath.compile(query); // $hasXPathInjection
88+
xpathStub.compile(query); // $hasXPathInjection
4789
expression3.evaluate(doc, XPathConstants.BOOLEAN);
4890

4991
// Good expression
@@ -63,9 +105,14 @@ public void handle(HttpServletRequest request) throws Exception {
63105
// Bad Dom4j
64106
org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
65107
org.dom4j.Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes()));
66-
document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']") // $hasXPathInjection
67-
.hasContent();
108+
document.selectObject("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
68109
document.selectNodes("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
110+
document.selectNodes("/users/user[@name='test']", "/users/user[@pass='" + pass + "']"); // Safe-ish
111+
document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
112+
document.valueOf("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
113+
document.numberValueOf("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
114+
document.matches("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
115+
document.createXPath("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
69116
}
70117
}
71118
}

java/ql/test/stubs/dom4j-2.1.1/org/dom4j/Document.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717

1818
public interface Document extends Branch {
1919

20-
public Node selectSingleNode(String xpathExpression);
21-
22-
public List selectNodes(String xpathExpression);
2320
}
2421

2522
/*
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3+
*
4+
* This software is open source.
5+
* See the bottom of this file for the licence.
6+
*/
7+
8+
/*
9+
* Adapted from DOM4J version 2.1.1 as available at
10+
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2.1.1-sources.jar
11+
* Only relevant stubs of this file have been retained for test purposes.
12+
*/
13+
14+
package org.dom4j;
15+
16+
public class InvalidXPathException extends IllegalArgumentException {
17+
public InvalidXPathException(String xpath) {
18+
}
19+
20+
public InvalidXPathException(String xpath, String reason) {
21+
}
22+
23+
}
24+
25+
/*
26+
* Redistribution and use of this software and associated documentation
27+
* ("Software"), with or without modification, are permitted provided that the
28+
* following conditions are met:
29+
*
30+
* 1. Redistributions of source code must retain copyright statements and
31+
* notices. Redistributions must also contain a copy of this document.
32+
*
33+
* 2. Redistributions in binary form must reproduce the above copyright notice,
34+
* this list of conditions and the following disclaimer in the documentation
35+
* and/or other materials provided with the distribution.
36+
*
37+
* 3. The name "DOM4J" must not be used to endorse or promote products derived
38+
* from this Software without prior written permission of MetaStuff, Ltd. For
39+
* written permission, please contact [email protected].
40+
*
41+
* 4. Products derived from this Software may not be called "DOM4J" nor may
42+
* "DOM4J" appear in their names without prior written permission of MetaStuff,
43+
* Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
44+
*
45+
* 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
46+
*
47+
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
48+
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50+
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
51+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57+
* POSSIBILITY OF SUCH DAMAGE.
58+
*
59+
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
60+
*/

java/ql/test/stubs/dom4j-2.1.1/org/dom4j/Node.java

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,72 @@
66
*/
77

88
/*
9-
* Adapted from DOM4J version 2.1.1 as available at
10-
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2.1.1-sources.jar
11-
* Only relevant stubs of this file have been retained for test purposes.
12-
*/
9+
* Adapted from DOM4J version 2.1.1 as available at
10+
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2.1.1-sources.jar
11+
* Only relevant stubs of this file have been retained for test purposes.
12+
*/
13+
1314
package org.dom4j;
1415

15-
public interface Node {
16+
import java.util.List;
17+
18+
import javax.xml.xpath.XPath;
19+
20+
public interface Node extends Cloneable {
21+
22+
List<Node> selectNodes(String xpathExpression);
23+
24+
Object selectObject(String xpathExpression);
25+
26+
List<Node> selectNodes(String xpathExpression, String comparisonXPathExpression);
27+
28+
List<Node> selectNodes(String xpathExpression, String comparisonXPathExpression, boolean removeDuplicates);
29+
30+
Node selectSingleNode(String xpathExpression);
31+
32+
String valueOf(String xpathExpression);
33+
34+
Number numberValueOf(String xpathExpression);
35+
36+
boolean matches(String xpathExpression);
37+
38+
XPath createXPath(String xpathExpression) throws InvalidXPathException;
1639

17-
public boolean hasContent();
1840
}
1941

2042
/*
43+
* Redistribution and use of this software and associated documentation
44+
* ("Software"), with or without modification, are permitted provided that the
45+
* following conditions are met:
46+
*
47+
* 1. Redistributions of source code must retain copyright statements and
48+
* notices. Redistributions must also contain a copy of this document.
49+
*
50+
* 2. Redistributions in binary form must reproduce the above copyright notice,
51+
* this list of conditions and the following disclaimer in the documentation
52+
* and/or other materials provided with the distribution.
53+
*
54+
* 3. The name "DOM4J" must not be used to endorse or promote products derived
55+
* from this Software without prior written permission of MetaStuff, Ltd. For
56+
* written permission, please contact [email protected].
57+
*
58+
* 4. Products derived from this Software may not be called "DOM4J" nor may
59+
* "DOM4J" appear in their names without prior written permission of MetaStuff,
60+
* Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
61+
*
62+
* 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
63+
*
64+
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
65+
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67+
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
68+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
69+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
70+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
71+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
72+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
73+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
74+
* POSSIBILITY OF SUCH DAMAGE.
75+
*
2176
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
22-
*
23-
* This software is open source. See the bottom of this file for the licence.
24-
*/
25-
26-
/*
27-
* Adapted from DOM4J version 2.1.1 as available at
28-
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2
29-
* .1.1-sources.jar Only relevant stubs of this file have been retained for test
30-
* purposes.
3177
*/

0 commit comments

Comments
 (0)