Merge pull request #3363 from ggolawski/xslt-injection

CodeQL query to detect XSLT injections
This commit is contained in:
Anders Schack-Mulligen
2020-09-01 11:03:19 +02:00
committed by GitHub
25 changed files with 677 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
import javax.xml.XMLConstants;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public void transform(Socket socket, String inputXml) throws Exception {
StreamSource xslt = new StreamSource(socket.getInputStream());
StreamSource xml = new StreamSource(new StringReader(inputXml));
StringWriter result = new StringWriter();
TransformerFactory factory = TransformerFactory.newInstance();
// BAD: User provided XSLT stylesheet is processed
factory.newTransformer(xslt).transform(xml, new StreamResult(result));
// GOOD: The secure processing mode is enabled
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.newTransformer(xslt).transform(xml, new StreamResult(result));
}

View File

@@ -0,0 +1,32 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>XSLT (Extensible Stylesheet Language Transformations) is a language for transforming XML
documents into other XML documents or other formats. Processing of unvalidated XSLT stylesheet can
let attacker to read arbitrary files from the filesystem or to execute arbitrary code.</p>
</overview>
<recommendation>
<p>The general recommendation is to not process untrusted XSLT stylesheets. If user provided
stylesheets must be processed, enable the secure processing mode.</p>
</recommendation>
<example>
<p>In the following examples, the code accepts an XSLT stylesheet from the user and processes it.
</p>
<p>In the first example, the user provided XSLT stylesheet is parsed and processed.</p>
<p>In the second example, secure processing mode is enabled.</p>
<sample src="XsltInjection.java" />
</example>
<references>
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/XSLT">XSLT</a>.</li>
<li>Java Tutorial: <a href="https://docs.oracle.com/javase/tutorial/jaxp/xslt/transformingXML.html">Transforming XML Data with XSLT</a>.</li>
<li><a href="https://blog.hunniccyber.com/ektron-cms-remote-code-execution-xslt-transform-injection-java/">XSLT Injection Basics</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,21 @@
/**
* @name XSLT transformation with user-controlled stylesheet
* @description Doing an XSLT transformation with user-controlled stylesheet can lead to
* information disclosure or execution of arbitrary code.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/xslt-injection
* @tags security
* external/cwe/cwe-074
*/
import java
import semmle.code.java.dataflow.FlowSources
import XsltInjectionLib
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, XsltInjectionFlowConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "XSLT transformation might include stylesheet from $@.",
source.getNode(), "this user input"

View File

@@ -0,0 +1,288 @@
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.XmlParsers
import DataFlow
/**
* A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
*/
class XsltInjectionFlowConfig extends TaintTracking::Configuration {
XsltInjectionFlowConfig() { this = "XsltInjectionFlowConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof XsltInjectionSink }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
xmlStreamReaderStep(node1, node2) or
xmlEventReaderStep(node1, node2) or
staxSourceStep(node1, node2) or
documentBuilderStep(node1, node2) or
domSourceStep(node1, node2) or
newTransformerOrTemplatesStep(node1, node2) or
newTransformerFromTemplatesStep(node1, node2) or
xsltCompilerStep(node1, node2) or
xsltExecutableStep(node1, node2) or
xsltPackageStep(node1, node2)
}
}
/** The class `javax.xml.transform.stax.StAXSource`. */
class TypeStAXSource extends Class {
TypeStAXSource() { this.hasQualifiedName("javax.xml.transform.stax", "StAXSource") }
}
/** The class `javax.xml.transform.dom.DOMSource`. */
class TypeDOMSource extends Class {
TypeDOMSource() { this.hasQualifiedName("javax.xml.transform.dom", "DOMSource") }
}
/** The interface `javax.xml.transform.Templates`. */
class TypeTemplates extends Interface {
TypeTemplates() { this.hasQualifiedName("javax.xml.transform", "Templates") }
}
/** The method `net.sf.saxon.s9api.XsltTransformer.transform`. */
class XsltTransformerTransformMethod extends Method {
XsltTransformerTransformMethod() {
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "XsltTransformer") and
this.hasName("transform")
}
}
/** The method `net.sf.saxon.s9api.Xslt30Transformer.transform`. */
class Xslt30TransformerTransformMethod extends Method {
Xslt30TransformerTransformMethod() {
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
this.hasName("transform")
}
}
/** The method `net.sf.saxon.s9api.Xslt30Transformer.applyTemplates`. */
class Xslt30TransformerApplyTemplatesMethod extends Method {
Xslt30TransformerApplyTemplatesMethod() {
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
this.hasName("applyTemplates")
}
}
/** The method `net.sf.saxon.s9api.Xslt30Transformer.callFunction`. */
class Xslt30TransformerCallFunctionMethod extends Method {
Xslt30TransformerCallFunctionMethod() {
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
this.hasName("callFunction")
}
}
/** The method `net.sf.saxon.s9api.Xslt30Transformer.callTemplate`. */
class Xslt30TransformerCallTemplateMethod extends Method {
Xslt30TransformerCallTemplateMethod() {
this.getDeclaringType().hasQualifiedName("net.sf.saxon.s9api", "Xslt30Transformer") and
this.hasName("callTemplate")
}
}
/** The class `net.sf.saxon.s9api.XsltCompiler`. */
class TypeXsltCompiler extends Class {
TypeXsltCompiler() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltCompiler") }
}
/** The class `net.sf.saxon.s9api.XsltExecutable`. */
class TypeXsltExecutable extends Class {
TypeXsltExecutable() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltExecutable") }
}
/** The class `net.sf.saxon.s9api.XsltPackage`. */
class TypeXsltPackage extends Class {
TypeXsltPackage() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltPackage") }
}
/** A data flow sink for unvalidated user input that is used in XSLT transformation. */
class XsltInjectionSink extends DataFlow::ExprNode {
XsltInjectionSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() and ma.getQualifier() = this.getExpr() |
ma instanceof TransformerTransform or
m instanceof XsltTransformerTransformMethod or
m instanceof Xslt30TransformerTransformMethod or
m instanceof Xslt30TransformerApplyTemplatesMethod or
m instanceof Xslt30TransformerCallFunctionMethod or
m instanceof Xslt30TransformerCallTemplateMethod
)
}
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
* `XMLStreamReader`, i.e. `XMLInputFactory.createXMLStreamReader(tainted)`.
*/
predicate xmlStreamReaderStep(ExprNode n1, ExprNode n2) {
exists(XmlInputFactoryStreamReader xmlStreamReader |
n1.asExpr() = xmlStreamReader.getSink() and
n2.asExpr() = xmlStreamReader
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
* `XMLEventReader`, i.e. `XMLInputFactory.createXMLEventReader(tainted)`.
*/
predicate xmlEventReaderStep(ExprNode n1, ExprNode n2) {
exists(XmlInputFactoryEventReader xmlEventReader |
n1.asExpr() = xmlEventReader.getSink() and
n2.asExpr() = xmlEventReader
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `XMLStreamReader` or
* `XMLEventReader` and `StAXSource`, i.e. `new StAXSource(tainted)`.
*/
predicate staxSourceStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeStAXSource |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` and `Document`,
* i.e. `DocumentBuilder.parse(tainted)`.
*/
predicate documentBuilderStep(ExprNode n1, ExprNode n2) {
exists(DocumentBuilderParse documentBuilder |
n1.asExpr() = documentBuilder.getSink() and
n2.asExpr() = documentBuilder
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Document` and `DOMSource`, i.e.
* `new DOMSource(tainted)`.
*/
predicate domSourceStep(ExprNode n1, ExprNode n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeDOMSource |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
*/
private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends DataFlow2::Configuration {
TransformerFactoryWithSecureProcessingFeatureFlowConfig() {
this = "TransformerFactoryWithSecureProcessingFeatureFlowConfig"
}
override predicate isSource(DataFlow::Node src) {
exists(Variable v | v = src.asExpr().(VarAccess).getVariable() |
exists(TransformerFactoryFeatureConfig config | config.getQualifier() = v.getAnAccess() |
config.enables(configSecureProcessing())
)
)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
ma.getMethod().getDeclaringType() instanceof TransformerFactory
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
/** A `ParserConfig` specific to `TransformerFactory`. */
private class TransformerFactoryFeatureConfig extends ParserConfig {
TransformerFactoryFeatureConfig() {
exists(Method m |
m = this.getMethod() and
m.getDeclaringType() instanceof TransformerFactory and
m.hasName("setFeature")
)
}
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
* `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
* `TransformerFactory.newTemplates(tainted)`.
*/
predicate newTransformerOrTemplatesStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
n1.asExpr() = ma.getAnArgument() and
n2.asExpr() = ma and
(
m.getDeclaringType() instanceof TransformerFactory and m.hasName("newTransformer")
or
m.getDeclaringType() instanceof TransformerFactory and m.hasName("newTemplates")
) and
not exists(TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
conf.hasFlowToExpr(ma.getQualifier())
)
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Templates` and `Transformer`,
* i.e. `tainted.newTransformer()`.
*/
predicate newTransformerFromTemplatesStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
m.getDeclaringType() instanceof TypeTemplates and
m.hasName("newTransformer")
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Source` or `URI` and
* `XsltExecutable` or `XsltPackage`, i.e. `XsltCompiler.compile(tainted)` or
* `XsltCompiler.loadExecutablePackage(tainted)` or `XsltCompiler.compilePackage(tainted)` or
* `XsltCompiler.loadLibraryPackage(tainted)`.
*/
predicate xsltCompilerStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
n1.asExpr() = ma.getArgument(0) and
n2.asExpr() = ma and
m.getDeclaringType() instanceof TypeXsltCompiler and
(
m.hasName("compile") or
m.hasName("loadExecutablePackage") or
m.hasName("compilePackage") or
m.hasName("loadLibraryPackage")
)
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltExecutable` and
* `XsltTransformer` or `Xslt30Transformer`, i.e. `XsltExecutable.load()` or
* `XsltExecutable.load30()`.
*/
predicate xsltExecutableStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
m.getDeclaringType() instanceof TypeXsltExecutable and
(m.hasName("load") or m.hasName("load30"))
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltPackage` and
* `XsltExecutable`, i.e. `XsltPackage.link()`.
*/
predicate xsltPackageStep(ExprNode n1, ExprNode n2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma and
m.getDeclaringType() instanceof TypeXsltPackage and
m.hasName("link")
)
}

View File

@@ -1172,3 +1172,15 @@ class SimpleXMLFormatterCall extends XmlParserCall {
override predicate isSafe() { none() }
}
/** A configuration for secure processing. */
Expr configSecureProcessing() {
result.(ConstantStringExpr).getStringValue() =
"http://javax.xml.XMLConstants/feature/secure-processing"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("FEATURE_SECURE_PROCESSING") and
f.getDeclaringType() instanceof XmlConstants
)
}

View File

@@ -0,0 +1,85 @@
edges
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:31:5:31:59 | newTransformer(...) |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:36:5:36:74 | newTransformer(...) |
| XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:43:5:43:59 | newTransformer(...) |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:48:5:48:74 | newTransformer(...) |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:53:5:53:59 | newTransformer(...) |
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:63:5:63:74 | newTransformer(...) |
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:76:5:76:34 | newTransformer(...) |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:83:5:83:34 | newTransformer(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:90:5:90:35 | load(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:91:5:91:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:92:5:92:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:93:5:93:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:94:5:94:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:95:5:95:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:96:5:96:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:97:5:97:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:98:5:98:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:99:5:99:37 | load30(...) |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:108:5:108:46 | load(...) |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:110:5:110:50 | load(...) |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:109:5:109:49 | load(...) |
nodes
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:31:5:31:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:36:5:36:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:40:45:40:70 | param : String | semmle.label | param : String |
| XsltInjection.java:43:5:43:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:48:5:48:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:53:5:53:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:58:5:58:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:63:5:63:74 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:68:5:68:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:76:5:76:34 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:83:5:83:34 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:90:5:90:35 | load(...) | semmle.label | load(...) |
| XsltInjection.java:91:5:91:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:92:5:92:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:93:5:93:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:94:5:94:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:95:5:95:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:96:5:96:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:97:5:97:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:98:5:98:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:99:5:99:37 | load30(...) | semmle.label | load30(...) |
| XsltInjection.java:103:36:103:61 | param : String | semmle.label | param : String |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| XsltInjection.java:108:5:108:46 | load(...) | semmle.label | load(...) |
| XsltInjection.java:109:5:109:49 | load(...) | semmle.label | load(...) |
| XsltInjection.java:110:5:110:50 | load(...) | semmle.label | load(...) |
#select
| XsltInjection.java:31:5:31:59 | newTransformer(...) | XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:31:5:31:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:30:44:30:66 | getInputStream(...) | this user input |
| XsltInjection.java:36:5:36:74 | newTransformer(...) | XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:36:5:36:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:35:66:35:88 | getInputStream(...) | this user input |
| XsltInjection.java:43:5:43:59 | newTransformer(...) | XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:43:5:43:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:40:45:40:70 | param | this user input |
| XsltInjection.java:48:5:48:74 | newTransformer(...) | XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:48:5:48:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:47:54:47:76 | getInputStream(...) | this user input |
| XsltInjection.java:53:5:53:59 | newTransformer(...) | XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:53:5:53:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:52:82:52:104 | getInputStream(...) | this user input |
| XsltInjection.java:58:5:58:59 | newTransformer(...) | XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:57:91:57:113 | getInputStream(...) | this user input |
| XsltInjection.java:63:5:63:74 | newTransformer(...) | XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:63:5:63:74 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:62:120:62:142 | getInputStream(...) | this user input |
| XsltInjection.java:68:5:68:59 | newTransformer(...) | XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:67:102:67:124 | getInputStream(...) | this user input |
| XsltInjection.java:76:5:76:34 | newTransformer(...) | XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:76:5:76:34 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:72:44:72:66 | getInputStream(...) | this user input |
| XsltInjection.java:83:5:83:34 | newTransformer(...) | XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:83:5:83:34 | newTransformer(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:80:44:80:66 | getInputStream(...) | this user input |
| XsltInjection.java:90:5:90:35 | load(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:90:5:90:35 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:91:5:91:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:91:5:91:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:92:5:92:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:92:5:92:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:93:5:93:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:93:5:93:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:94:5:94:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:94:5:94:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:95:5:95:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:95:5:95:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:96:5:96:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:96:5:96:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:97:5:97:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:97:5:97:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:98:5:98:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:98:5:98:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:99:5:99:37 | load30(...) | XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:99:5:99:37 | load30(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:87:44:87:66 | getInputStream(...) | this user input |
| XsltInjection.java:108:5:108:46 | load(...) | XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:108:5:108:46 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:103:36:103:61 | param | this user input |
| XsltInjection.java:109:5:109:49 | load(...) | XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:109:5:109:49 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:105:44:105:66 | getInputStream(...) | this user input |
| XsltInjection.java:110:5:110:50 | load(...) | XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:110:5:110:50 | load(...) | XSLT transformation might include stylesheet from $@. | XsltInjection.java:103:36:103:61 | param | this user input |

View File

@@ -0,0 +1,127 @@
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.Socket;
import java.net.URI;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.xml.sax.InputSource;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.s9api.XsltCompiler;
@Controller
public class XsltInjection {
public void testStreamSourceInputStream(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
}
public void testStreamSourceReader(Socket socket) throws Exception {
StreamSource source = new StreamSource(new InputStreamReader(socket.getInputStream()));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
}
@RequestMapping
public void testStreamSourceInjectedParam(@RequestParam String param) throws Exception {
String xslt = "<xsl:stylesheet [...]" + param + "</xsl:stylesheet>";
StreamSource source = new StreamSource(new StringReader(xslt));
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
}
public void testSAXSourceInputStream(Socket socket) throws Exception {
SAXSource source = new SAXSource(new InputSource(socket.getInputStream()));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
}
public void testSAXSourceReader(Socket socket) throws Exception {
SAXSource source = new SAXSource(null, new InputSource(new InputStreamReader(socket.getInputStream())));
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
}
public void testStAXSourceEventReader(Socket socket) throws Exception {
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLEventReader(socket.getInputStream()));
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
}
public void testStAXSourceEventStream(Socket socket) throws Exception {
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLStreamReader(null, new InputStreamReader(socket.getInputStream())));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null);
}
public void testDOMSource(Socket socket) throws Exception {
DOMSource source = new DOMSource(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(socket.getInputStream()));
TransformerFactory.newInstance().newTransformer(source).transform(null, null);
}
public void testDisabledXXE(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
factory.newTransformer(source).transform(null, null);
}
public void testFeatureSecureProcessingDisabled(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
factory.newTransformer(source).transform(null, null);
}
public void testSaxon(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.compile(source).load().transform();
compiler.compile(source).load30().transform(null, null);
compiler.compile(source).load30().applyTemplates((Source) null);
compiler.compile(source).load30().applyTemplates((Source) null, null);
compiler.compile(source).load30().applyTemplates((XdmValue) null);
compiler.compile(source).load30().applyTemplates((XdmValue) null, null);
compiler.compile(source).load30().callFunction(null, null);
compiler.compile(source).load30().callFunction(null, null, null);
compiler.compile(source).load30().callTemplate(null);
compiler.compile(source).load30().callTemplate(null, null);
}
@RequestMapping
public void testSaxonXsltPackage(@RequestParam String param, Socket socket) throws Exception {
URI uri = new URI(param);
StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.loadExecutablePackage(uri).load().transform();
compiler.compilePackage(source).link().load().transform();
compiler.loadLibraryPackage(uri).link().load().transform();
}
public void testOkFeatureSecureProcessing(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.newTransformer(source).transform(null, null);
}
public void testOkSaxon(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.compile(source).load().close();
compiler.compile((Source) new Object()).load().transform();
}
}

View File

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

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/Saxon-HE-9.9.1-7

View File

@@ -0,0 +1,8 @@
package net.sf.saxon;
import net.sf.saxon.lib.*;
import net.sf.saxon.om.*;
public class Configuration implements SourceResolver, NotationSet {
public interface ApiProvider {}
}

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.lib;
public interface SourceResolver { }

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.om;
public interface NotationSet { }

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
abstract class AbstractXsltTransformer { }

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
public interface Destination { }

View File

@@ -0,0 +1,9 @@
package net.sf.saxon.s9api;
import net.sf.saxon.Configuration;
public class Processor implements Configuration.ApiProvider {
public Processor(boolean licensedEdition) {}
public XsltCompiler newXsltCompiler() { return null; }
}

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
public class QName { }

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
public class SaxonApiException extends Exception { }

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
public class SaxonApiUncheckedException extends RuntimeException {}

View File

@@ -0,0 +1,3 @@
package net.sf.saxon.s9api;
public abstract class XdmItem extends XdmValue { }

View File

@@ -0,0 +1,8 @@
package net.sf.saxon.s9api;
import java.lang.Iterable;
import java.util.Iterator;
public class XdmValue implements Iterable<XdmItem> {
public Iterator<XdmItem> iterator() throws SaxonApiUncheckedException { return null; }
}

View File

@@ -0,0 +1,15 @@
package net.sf.saxon.s9api;
import javax.xml.transform.Source;
public class Xslt30Transformer extends AbstractXsltTransformer {
public void transform(Source source, Destination destination) throws SaxonApiException {}
public void applyTemplates(Source source, Destination destination) throws SaxonApiException {}
public XdmValue applyTemplates(Source source) throws SaxonApiException { return null; }
public void applyTemplates(XdmValue selection, Destination destination) throws SaxonApiException {}
public XdmValue applyTemplates(XdmValue selection) throws SaxonApiException { return null; }
public XdmValue callFunction(QName function, XdmValue[] arguments) throws SaxonApiException { return null; }
public void callFunction(QName function, XdmValue[] arguments, Destination destination) throws SaxonApiException {}
public XdmValue callTemplate(QName templateName) throws SaxonApiException { return null; }
public void callTemplate(QName templateName, Destination destination) throws SaxonApiException {}
}

View File

@@ -0,0 +1,11 @@
package net.sf.saxon.s9api;
import javax.xml.transform.Source;
import java.net.URI;
public class XsltCompiler {
public XsltExecutable compile(Source source) throws SaxonApiException { return null; }
public XsltExecutable loadExecutablePackage(URI location) throws SaxonApiException { return null; }
public XsltPackage compilePackage(Source source) throws SaxonApiException { return null; }
public XsltPackage loadLibraryPackage(URI location) throws SaxonApiException { return null; }
}

View File

@@ -0,0 +1,6 @@
package net.sf.saxon.s9api;
public class XsltExecutable {
public XsltTransformer load() { return null; }
public Xslt30Transformer load30() { return null; }
}

View File

@@ -0,0 +1,5 @@
package net.sf.saxon.s9api;
public class XsltPackage {
public XsltExecutable link() throws SaxonApiException { return null; }
}

View File

@@ -0,0 +1,6 @@
package net.sf.saxon.s9api;
public class XsltTransformer extends AbstractXsltTransformer implements Destination {
public void transform() throws SaxonApiException {}
public void close() {}
}