mirror of
https://github.com/github/codeql.git
synced 2026-05-03 04:39:29 +02:00
WIP: XPath Injection promotion
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import javax.xml.*;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class A {
|
||||
public void handle(HttpServletRequest request) throws Exception {
|
||||
final String xmlStr = "<users>" + " <user name=\"aaa\" pass=\"pass1\"></user>"
|
||||
+ " <user name=\"bbb\" pass=\"pass2\"></user>" + "</users>";
|
||||
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
|
||||
domFactory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = domFactory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
|
||||
|
||||
XPathFactory factory = XPathFactory.newInstance();
|
||||
XPath xpath = factory.newXPath();
|
||||
|
||||
// Injectable data
|
||||
String user = request.getParameter("user");
|
||||
String pass = request.getParameter("pass");
|
||||
if (user != null && pass != null) {
|
||||
boolean isExist = false;
|
||||
|
||||
// Bad expression
|
||||
String expression1 = "/users/user[@name='" + user + "' and @pass='" + pass + "']";
|
||||
isExist = (boolean) xpath.evaluate(expression1, doc, XPathConstants.BOOLEAN); // $hasXPathInjection
|
||||
System.out.println(isExist);
|
||||
|
||||
// Bad expression
|
||||
XPathExpression expression2 = xpath.compile("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
|
||||
isExist = (boolean) expression2.evaluate(doc, XPathConstants.BOOLEAN);
|
||||
System.out.println(isExist);
|
||||
|
||||
// Bad expression
|
||||
StringBuffer sb = new StringBuffer("/users/user[@name=");
|
||||
sb.append(user);
|
||||
sb.append("' and @pass='");
|
||||
sb.append(pass);
|
||||
sb.append("']");
|
||||
String query = sb.toString();
|
||||
XPathExpression expression3 = xpath.compile(query); // $hasXPathInjection
|
||||
isExist = (boolean) expression3.evaluate(doc, XPathConstants.BOOLEAN);
|
||||
System.out.println(isExist);
|
||||
|
||||
// Good expression
|
||||
String expression4 = "/users/user[@name=$user and @pass=$pass]";
|
||||
xpath.setXPathVariableResolver(v -> {
|
||||
switch (v.getLocalPart()) {
|
||||
case "user":
|
||||
return user;
|
||||
case "pass":
|
||||
return pass;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
});
|
||||
isExist = (boolean) xpath.evaluate(expression4, doc, XPathConstants.BOOLEAN);
|
||||
System.out.println(isExist);
|
||||
|
||||
// Bad Dom4j
|
||||
org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
|
||||
org.dom4j.Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes()));
|
||||
isExist = document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']") // $hasXPathInjection
|
||||
.hasContent();
|
||||
document.selectNodes("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.XPath
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class HasXPathInjectionTest extends InlineExpectationsTest {
|
||||
HasXPathInjectionTest() { this = "HasXPathInjectionTest" }
|
||||
|
||||
override string getARelevantTag() { result = "hasXPathInjection" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasXPathInjection" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, XPathInjectionConfiguration conf |
|
||||
conf.hasFlow(src, sink)
|
||||
|
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/dom4j-2.1.1:${testdir}/../../../../stubs/servlet-api-2.4
|
||||
@@ -13,7 +13,13 @@
|
||||
|
||||
package org.dom4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Document {
|
||||
|
||||
public Node selectSingleNode(String xpathExpression);
|
||||
|
||||
public List selectNodes(String xpathExpression);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
31
java/ql/test/stubs/dom4j-2.1.1/org/dom4j/Node.java
Normal file
31
java/ql/test/stubs/dom4j-2.1.1/org/dom4j/Node.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
* See the bottom of this file for the licence.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from DOM4J version 2.1.1 as available at
|
||||
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2.1.1-sources.jar
|
||||
* Only relevant stubs of this file have been retained for test purposes.
|
||||
*/
|
||||
package org.dom4j;
|
||||
|
||||
public interface Node {
|
||||
|
||||
public boolean hasContent();
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
|
||||
*
|
||||
* This software is open source. See the bottom of this file for the licence.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from DOM4J version 2.1.1 as available at
|
||||
* https://search.maven.org/remotecontent?filepath=org/dom4j/dom4j/2.1.1/dom4j-2
|
||||
* .1.1-sources.jar Only relevant stubs of this file have been retained for test
|
||||
* purposes.
|
||||
*/
|
||||
Reference in New Issue
Block a user