Merge pull request #6097 from atorralba/atorralba/promote-xslt-injection

Java: Promote XSLT Injection from experimental
This commit is contained in:
Anders Schack-Mulligen
2021-09-27 13:14:57 +02:00
committed by GitHub
31 changed files with 409 additions and 455 deletions

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The query "XSLT transformation with user-controlled stylesheet" (`java/xslt-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @ggolawski](https://github.com/github/codeql/pull/3363).

View File

@@ -110,6 +110,7 @@ private module Frameworks {
private import semmle.code.java.security.MvelInjection private import semmle.code.java.security.MvelInjection
private import semmle.code.java.security.OgnlInjection private import semmle.code.java.security.OgnlInjection
private import semmle.code.java.security.XPath private import semmle.code.java.security.XPath
private import semmle.code.java.security.XsltInjection
private import semmle.code.java.frameworks.android.Android private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.frameworks.android.SQLite private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.Jdbc private import semmle.code.java.frameworks.Jdbc

View File

@@ -0,0 +1,248 @@
/** Provides classes to reason about XSLT injection vulnerabilities. */
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
/**
* A data flow sink for unvalidated user input that is used in XSLT transformation.
* Extend this class to add your own XSLT Injection sinks.
*/
abstract class XsltInjectionSink extends DataFlow::Node { }
/** A default sink representing methods susceptible to XSLT Injection attacks. */
private class DefaultXsltInjectionSink extends XsltInjectionSink {
DefaultXsltInjectionSink() { sinkNode(this, "xslt") }
}
private class DefaultXsltInjectionSinkModel extends SinkModelCsv {
override predicate row(string row) {
row =
[
"javax.xml.transform;Transformer;false;transform;;;Argument[-1];xslt",
"net.sf.saxon.s9api;XsltTransformer;false;transform;;;Argument[-1];xslt",
"net.sf.saxon.s9api;Xslt30Transformer;false;transform;;;Argument[-1];xslt",
"net.sf.saxon.s9api;Xslt30Transformer;false;applyTemplates;;;Argument[-1];xslt",
"net.sf.saxon.s9api;Xslt30Transformer;false;callFunction;;;Argument[-1];xslt",
"net.sf.saxon.s9api;Xslt30Transformer;false;callTemplate;;;Argument[-1];xslt"
]
}
}
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to the `XsltInjectionFlowConfig`.
*/
class XsltInjectionAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for the `XsltInjectionFlowConfig` configuration.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/** A set of additional taint steps to consider when taint tracking XSLT related data flows. */
private class DefaultXsltInjectionAdditionalTaintStep extends XsltInjectionAdditionalTaintStep {
override predicate step(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
newTransformerFromTemplatesStep(node1, node2) or
xsltCompilerStep(node1, node2) or
xsltExecutableStep(node1, node2) or
xsltPackageStep(node1, node2)
}
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
* `XMLStreamReader`, i.e. `XMLInputFactory.createXMLStreamReader(tainted)`.
*/
private predicate xmlStreamReaderStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(XmlInputFactoryStreamReader xmlStreamReader |
if xmlStreamReader.getMethod().getParameterType(0) instanceof TypeString
then n1.asExpr() = xmlStreamReader.getArgument(1)
else n1.asExpr() = xmlStreamReader.getArgument(0)
|
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)`.
*/
private predicate xmlEventReaderStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(XmlInputFactoryEventReader xmlEventReader |
if xmlEventReader.getMethod().getParameterType(0) instanceof TypeString
then n1.asExpr() = xmlEventReader.getArgument(1)
else n1.asExpr() = xmlEventReader.getArgument(0)
|
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)`.
*/
private predicate staxSourceStep(DataFlow::Node n1, DataFlow::Node 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)`.
*/
private predicate documentBuilderStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(DocumentBuilderParse documentBuilder |
n1.asExpr() = documentBuilder.getArgument(0) and
n2.asExpr() = documentBuilder
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Document` and `DOMSource`, i.e.
* `new DOMSource(tainted)`.
*/
private predicate domSourceStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeDOMSource |
n1.asExpr() = cc.getAnArgument() and
n2.asExpr() = cc
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `Templates` and `Transformer`,
* i.e. `tainted.newTransformer()`.
*/
private predicate newTransformerFromTemplatesStep(DataFlow::Node n1, DataFlow::Node 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)`.
*/
private predicate xsltCompilerStep(DataFlow::Node n1, DataFlow::Node 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", "loadExecutablePackage", "compilePackage", "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()`.
*/
private predicate xsltExecutableStep(DataFlow::Node n1, DataFlow::Node 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", "load30"])
)
}
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `XsltPackage` and
* `XsltExecutable`, i.e. `XsltPackage.link()`.
*/
private predicate xsltPackageStep(DataFlow::Node n1, DataFlow::Node 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")
)
}
/** The class `javax.xml.transform.stax.StAXSource`. */
private class TypeStAXSource extends Class {
TypeStAXSource() { this.hasQualifiedName("javax.xml.transform.stax", "StAXSource") }
}
/** The class `javax.xml.transform.dom.DOMSource`. */
private class TypeDOMSource extends Class {
TypeDOMSource() { this.hasQualifiedName("javax.xml.transform.dom", "DOMSource") }
}
/** The interface `javax.xml.transform.Templates`. */
private class TypeTemplates extends Interface {
TypeTemplates() { this.hasQualifiedName("javax.xml.transform", "Templates") }
}
/** The class `net.sf.saxon.s9api.XsltCompiler`. */
private class TypeXsltCompiler extends Class {
TypeXsltCompiler() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltCompiler") }
}
/** The class `net.sf.saxon.s9api.XsltExecutable`. */
private class TypeXsltExecutable extends Class {
TypeXsltExecutable() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltExecutable") }
}
/** The class `net.sf.saxon.s9api.XsltPackage`. */
private class TypeXsltPackage extends Class {
TypeXsltPackage() { this.hasQualifiedName("net.sf.saxon.s9api", "XsltPackage") }
}
// XmlParsers classes
/** A call to `DocumentBuilder.parse`. */
private class DocumentBuilderParse extends MethodAccess {
DocumentBuilderParse() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof DocumentBuilder and
m.hasName("parse")
)
}
}
/** The class `javax.xml.parsers.DocumentBuilder`. */
private class DocumentBuilder extends RefType {
DocumentBuilder() { this.hasQualifiedName("javax.xml.parsers", "DocumentBuilder") }
}
/** A call to `XMLInputFactory.createXMLStreamReader`. */
private class XmlInputFactoryStreamReader extends MethodAccess {
XmlInputFactoryStreamReader() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof XmlInputFactory and
m.hasName("createXMLStreamReader")
)
}
}
/** A call to `XMLInputFactory.createEventReader`. */
private class XmlInputFactoryEventReader extends MethodAccess {
XmlInputFactoryEventReader() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof XmlInputFactory and
m.hasName("createXMLEventReader")
)
}
}
/** The class `javax.xml.stream.XMLInputFactory`. */
private class XmlInputFactory extends RefType {
XmlInputFactory() { this.hasQualifiedName("javax.xml.stream", "XMLInputFactory") }
}

View File

@@ -0,0 +1,90 @@
/** Provides taint tracking configurations to be used in XSLT injection queries. */
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.XmlParsers
import semmle.code.java.security.XsltInjection
/**
* 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) {
any(XsltInjectionAdditionalTaintStep c).step(node1, node2)
}
}
/**
* A set of additional taint steps to consider when taint tracking XSLT related data flows.
* These steps use data flow logic themselves.
*/
private class DataFlowXsltInjectionAdditionalTaintStep extends XsltInjectionAdditionalTaintStep {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
newTransformerOrTemplatesStep(node1, node2)
}
}
/**
* 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)`.
*/
private predicate newTransformerOrTemplatesStep(DataFlow::Node n1, DataFlow::Node 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", "newTemplates"]) and
not exists(TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
conf.hasFlowToExpr(ma.getQualifier())
)
)
}
/**
* 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")
)
}
}

View File

@@ -4,12 +4,12 @@
<qhelp> <qhelp>
<overview> <overview>
<p>XSLT (Extensible Stylesheet Language Transformations) is a language for transforming XML <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 documents into other XML documents or other formats. Processing unvalidated XSLT stylesheets can
let attacker to read arbitrary files from the filesystem or to execute arbitrary code.</p> allow attackers to read arbitrary files from the filesystem or to execute arbitrary code.</p>
</overview> </overview>
<recommendation> <recommendation>
<p>The general recommendation is to not process untrusted XSLT stylesheets. If user provided <p>The general recommendation is to not process untrusted XSLT stylesheets. If user-provided
stylesheets must be processed, enable the secure processing mode.</p> stylesheets must be processed, enable the secure processing mode.</p>
</recommendation> </recommendation>
@@ -17,7 +17,7 @@ stylesheets must be processed, enable the secure processing mode.</p>
<p>In the following examples, the code accepts an XSLT stylesheet from the user and processes it. <p>In the following examples, the code accepts an XSLT stylesheet from the user and processes it.
</p> </p>
<p>In the first example, the user provided XSLT stylesheet is parsed and processed.</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> <p>In the second example, secure processing mode is enabled.</p>

View File

@@ -1,6 +1,6 @@
/** /**
* @name XSLT transformation with user-controlled stylesheet * @name XSLT transformation with user-controlled stylesheet
* @description Doing an XSLT transformation with user-controlled stylesheet can lead to * @description Performing an XSLT transformation with user-controlled stylesheets can lead to
* information disclosure or execution of arbitrary code. * information disclosure or execution of arbitrary code.
* @kind path-problem * @kind path-problem
* @problem.severity error * @problem.severity error
@@ -11,8 +11,7 @@
*/ */
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.XsltInjectionQuery
import XsltInjectionLib
import DataFlow::PathGraph import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, XsltInjectionFlowConfig conf from DataFlow::PathNode source, DataFlow::PathNode sink, XsltInjectionFlowConfig conf

View File

@@ -1,288 +0,0 @@
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

@@ -1,122 +0,0 @@
edges
| XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource | XsltInjection.java:31:5:31:59 | newTransformer(...) |
| XsltInjection.java:30:44:30:66 | getInputStream(...) : InputStream | XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:27:35:90 | new StreamSource(...) : StreamSource | XsltInjection.java:36:5:36:74 | newTransformer(...) |
| XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:35:27:35:90 | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:66:35:88 | getInputStream(...) : InputStream | XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:40:45:40:70 | param : String | XsltInjection.java:42:61:42:64 | xslt : String |
| XsltInjection.java:42:27:42:66 | new StreamSource(...) : StreamSource | XsltInjection.java:43:5:43:59 | newTransformer(...) |
| XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader | XsltInjection.java:42:27:42:66 | new StreamSource(...) : StreamSource |
| XsltInjection.java:42:61:42:64 | xslt : String | XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader |
| XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource | XsltInjection.java:48:5:48:74 | newTransformer(...) |
| XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource | XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource |
| XsltInjection.java:47:54:47:76 | getInputStream(...) : InputStream | XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource |
| XsltInjection.java:52:24:52:107 | new SAXSource(...) : SAXSource | XsltInjection.java:53:5:53:59 | newTransformer(...) |
| XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource | XsltInjection.java:52:24:52:107 | new SAXSource(...) : SAXSource |
| XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource |
| XsltInjection.java:52:82:52:104 | getInputStream(...) : InputStream | XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:57:91:57:113 | getInputStream(...) : InputStream | XsltInjection.java:58:5:58:59 | newTransformer(...) |
| XsltInjection.java:62:98:62:143 | new InputStreamReader(...) : InputStreamReader | XsltInjection.java:63:5:63:74 | newTransformer(...) |
| XsltInjection.java:62:120:62:142 | getInputStream(...) : InputStream | XsltInjection.java:62:98:62:143 | new InputStreamReader(...) : InputStreamReader |
| XsltInjection.java:67:102:67:124 | getInputStream(...) : InputStream | XsltInjection.java:68:5:68:59 | newTransformer(...) |
| XsltInjection.java:72:27:72:67 | new StreamSource(...) : StreamSource | XsltInjection.java:76:5:76:34 | newTransformer(...) |
| XsltInjection.java:72:44:72:66 | getInputStream(...) : InputStream | XsltInjection.java:72:27:72:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:80:27:80:67 | new StreamSource(...) : StreamSource | XsltInjection.java:83:5:83:34 | newTransformer(...) |
| XsltInjection.java:80:44:80:66 | getInputStream(...) : InputStream | XsltInjection.java:80:27:80:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:90:5:90:35 | load(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:91:5:91:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:92:5:92:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:93:5:93:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:94:5:94:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:95:5:95:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:96:5:96:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:97:5:97:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:98:5:98:37 | load30(...) |
| XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource | XsltInjection.java:99:5:99:37 | load30(...) |
| XsltInjection.java:87:44:87:66 | getInputStream(...) : InputStream | XsltInjection.java:87:27:87:67 | new StreamSource(...) : StreamSource |
| XsltInjection.java:103:36:103:61 | param : String | XsltInjection.java:104:23:104:27 | param : String |
| XsltInjection.java:104:15:104:28 | new URI(...) : URI | XsltInjection.java:108:5:108:46 | load(...) |
| XsltInjection.java:104:15:104:28 | new URI(...) : URI | XsltInjection.java:110:5:110:50 | load(...) |
| XsltInjection.java:104:23:104:27 | param : String | XsltInjection.java:104:15:104:28 | new URI(...) : URI |
| XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource | XsltInjection.java:109:5:109:49 | load(...) |
| XsltInjection.java:105:44:105:66 | getInputStream(...) : InputStream | XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource |
nodes
| XsltInjection.java:30:27:30:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| 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:27:35:90 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:35:44:35:89 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| 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:42:27:42:66 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| XsltInjection.java:42:44:42:65 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader |
| XsltInjection.java:42:61:42:64 | xslt : String | semmle.label | xslt : String |
| XsltInjection.java:43:5:43:59 | newTransformer(...) | semmle.label | newTransformer(...) |
| XsltInjection.java:47:24:47:78 | new SAXSource(...) : SAXSource | semmle.label | new SAXSource(...) : SAXSource |
| XsltInjection.java:47:38:47:77 | new InputSource(...) : InputSource | semmle.label | new InputSource(...) : InputSource |
| 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:24:52:107 | new SAXSource(...) : SAXSource | semmle.label | new SAXSource(...) : SAXSource |
| XsltInjection.java:52:44:52:106 | new InputSource(...) : InputSource | semmle.label | new InputSource(...) : InputSource |
| XsltInjection.java:52:60:52:105 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| 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:98:62:143 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
| 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:27:72:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| 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:27:80:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| 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:27:87:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| 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:104:15:104:28 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| XsltInjection.java:104:23:104:27 | param : String | semmle.label | param : String |
| XsltInjection.java:105:27:105:67 | new StreamSource(...) : StreamSource | semmle.label | new StreamSource(...) : StreamSource |
| 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(...) |
subpaths
#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

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

View File

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

View File

@@ -25,47 +25,51 @@ import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.s9api.XsltCompiler; import net.sf.saxon.s9api.XsltCompiler;
@Controller @Controller
public class XsltInjection { public class XsltInjectionTest {
public void testStreamSourceInputStream(Socket socket) throws Exception { public void testStreamSourceInputStream(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory.newInstance().newTransformer(source).transform(null, null); TransformerFactory.newInstance().newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testStreamSourceReader(Socket socket) throws Exception { public void testStreamSourceReader(Socket socket) throws Exception {
StreamSource source = new StreamSource(new InputStreamReader(socket.getInputStream())); StreamSource source = new StreamSource(new InputStreamReader(socket.getInputStream()));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); // $hasXsltInjection
} }
@RequestMapping @RequestMapping
public void testStreamSourceInjectedParam(@RequestParam String param) throws Exception { public void testStreamSourceInjectedParam(@RequestParam String param) throws Exception {
String xslt = "<xsl:stylesheet [...]" + param + "</xsl:stylesheet>"; String xslt = "<xsl:stylesheet [...]" + param + "</xsl:stylesheet>";
StreamSource source = new StreamSource(new StringReader(xslt)); StreamSource source = new StreamSource(new StringReader(xslt));
TransformerFactory.newInstance().newTransformer(source).transform(null, null); TransformerFactory.newInstance().newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testSAXSourceInputStream(Socket socket) throws Exception { public void testSAXSourceInputStream(Socket socket) throws Exception {
SAXSource source = new SAXSource(new InputSource(socket.getInputStream())); SAXSource source = new SAXSource(new InputSource(socket.getInputStream()));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); // $hasXsltInjection
} }
public void testSAXSourceReader(Socket socket) throws Exception { public void testSAXSourceReader(Socket socket) throws Exception {
SAXSource source = new SAXSource(null, new InputSource(new InputStreamReader(socket.getInputStream()))); SAXSource source =
TransformerFactory.newInstance().newTransformer(source).transform(null, null); new SAXSource(null, new InputSource(new InputStreamReader(socket.getInputStream())));
TransformerFactory.newInstance().newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testStAXSourceEventReader(Socket socket) throws Exception { public void testStAXSourceEventReader(Socket socket) throws Exception {
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLEventReader(socket.getInputStream())); StAXSource source =
TransformerFactory.newInstance().newTransformer(source).transform(null, null); new StAXSource(XMLInputFactory.newInstance().createXMLEventReader(socket.getInputStream()));
TransformerFactory.newInstance().newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testStAXSourceEventStream(Socket socket) throws Exception { public void testStAXSourceEventStream(Socket socket) throws Exception {
StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLStreamReader(null, new InputStreamReader(socket.getInputStream()))); StAXSource source = new StAXSource(XMLInputFactory.newInstance().createXMLStreamReader(null,
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); new InputStreamReader(socket.getInputStream())));
TransformerFactory.newInstance().newTemplates(source).newTransformer().transform(null, null); // $hasXsltInjection
} }
public void testDOMSource(Socket socket) throws Exception { public void testDOMSource(Socket socket) throws Exception {
DOMSource source = new DOMSource(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(socket.getInputStream())); DOMSource source = new DOMSource(
TransformerFactory.newInstance().newTransformer(source).transform(null, null); DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(socket.getInputStream()));
TransformerFactory.newInstance().newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testDisabledXXE(Socket socket) throws Exception { public void testDisabledXXE(Socket socket) throws Exception {
@@ -73,30 +77,30 @@ public class XsltInjection {
TransformerFactory factory = TransformerFactory.newInstance(); TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
factory.newTransformer(source).transform(null, null); factory.newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testFeatureSecureProcessingDisabled(Socket socket) throws Exception { public void testFeatureSecureProcessingDisabled(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory factory = TransformerFactory.newInstance(); TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
factory.newTransformer(source).transform(null, null); factory.newTransformer(source).transform(null, null); // $hasXsltInjection
} }
public void testSaxon(Socket socket) throws Exception { public void testSaxon(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler(); XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.compile(source).load().transform(); compiler.compile(source).load().transform(); // $hasXsltInjection
compiler.compile(source).load30().transform(null, null); compiler.compile(source).load30().transform(null, null); // $hasXsltInjection
compiler.compile(source).load30().applyTemplates((Source) null); compiler.compile(source).load30().applyTemplates((Source) null); // $hasXsltInjection
compiler.compile(source).load30().applyTemplates((Source) null, null); compiler.compile(source).load30().applyTemplates((Source) null, null); // $hasXsltInjection
compiler.compile(source).load30().applyTemplates((XdmValue) null); compiler.compile(source).load30().applyTemplates((XdmValue) null); // $hasXsltInjection
compiler.compile(source).load30().applyTemplates((XdmValue) null, null); compiler.compile(source).load30().applyTemplates((XdmValue) null, null); // $hasXsltInjection
compiler.compile(source).load30().callFunction(null, null); compiler.compile(source).load30().callFunction(null, null); // $hasXsltInjection
compiler.compile(source).load30().callFunction(null, null, null); compiler.compile(source).load30().callFunction(null, null, null); // $hasXsltInjection
compiler.compile(source).load30().callTemplate(null); compiler.compile(source).load30().callTemplate(null); // $hasXsltInjection
compiler.compile(source).load30().callTemplate(null, null); compiler.compile(source).load30().callTemplate(null, null); // $hasXsltInjection
} }
@RequestMapping @RequestMapping
@@ -105,23 +109,23 @@ public class XsltInjection {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler(); XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.loadExecutablePackage(uri).load().transform(); compiler.loadExecutablePackage(uri).load().transform(); // $hasXsltInjection
compiler.compilePackage(source).link().load().transform(); compiler.compilePackage(source).link().load().transform(); // $hasXsltInjection
compiler.loadLibraryPackage(uri).link().load().transform(); compiler.loadLibraryPackage(uri).link().load().transform(); // $hasXsltInjection
} }
public void testOkFeatureSecureProcessing(Socket socket) throws Exception { public void testOkFeatureSecureProcessing(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
TransformerFactory factory = TransformerFactory.newInstance(); TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.newTransformer(source).transform(null, null); factory.newTransformer(source).transform(null, null); // Safe
} }
public void testOkSaxon(Socket socket) throws Exception { public void testOkSaxon(Socket socket) throws Exception {
StreamSource source = new StreamSource(socket.getInputStream()); StreamSource source = new StreamSource(socket.getInputStream());
XsltCompiler compiler = new Processor(true).newXsltCompiler(); XsltCompiler compiler = new Processor(true).newXsltCompiler();
compiler.compile(source).load().close(); compiler.compile(source).load().close(); // Safe
compiler.compile((Source) new Object()).load().transform(); compiler.compile((Source) new Object()).load().transform(); // Safe
} }
} }

View File

@@ -0,0 +1,22 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.XsltInjectionQuery
import TestUtilities.InlineExpectationsTest
class HasXsltInjectionTest extends InlineExpectationsTest {
HasXsltInjectionTest() { this = "HasXsltInjectionTest" }
override string getARelevantTag() { result = "hasXsltInjection" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasXsltInjection" and
exists(DataFlow::Node src, DataFlow::Node sink, XsltInjectionFlowConfig conf |
conf.hasFlow(src, sink)
|
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
}
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2 //semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/Saxon-HE-9.9.1-7