Skip to content

Commit 935e22d

Browse files
authored
Merge pull request github#12139 from atorralba/atorralba/java/xxe-local-query
Java: Add local version of the XXE query
2 parents 781aab3 + 1c57aa0 commit 935e22d

File tree

8 files changed

+141
-33
lines changed

8 files changed

+141
-33
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/** Provides classes to reason about XML eXternal Entity (XXE) vulnerabilities. */
2+
3+
import java
4+
private import semmle.code.java.dataflow.DataFlow
5+
6+
/** A node where insecure XML parsing takes place. */
7+
abstract class XxeSink extends DataFlow::Node { }
8+
9+
/** A node that acts as a sanitizer in configurations realted to XXE vulnerabilities. */
10+
abstract class XxeSanitizer extends DataFlow::Node { }
11+
12+
/**
13+
* A unit class for adding additional taint steps.
14+
*
15+
* Extend this class to add additional taint steps that should apply to flows related to
16+
* XXE vulnerabilities.
17+
*/
18+
class XxeAdditionalTaintStep extends Unit {
19+
/**
20+
* Holds if the step from `node1` to `node2` should be considered a taint
21+
* step for flows related to XXE vulnerabilities.
22+
*/
23+
abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
24+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/** Provides taint tracking configurations to be used in local XXE queries. */
2+
3+
import java
4+
private import semmle.code.java.dataflow.FlowSources
5+
private import semmle.code.java.dataflow.TaintTracking
6+
private import semmle.code.java.security.XxeQuery
7+
8+
/**
9+
* A taint-tracking configuration for unvalidated local user input that is used in XML external entity expansion.
10+
*/
11+
class XxeLocalConfig extends TaintTracking::Configuration {
12+
XxeLocalConfig() { this = "XxeLocalConfig" }
13+
14+
override predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
15+
16+
override predicate isSink(DataFlow::Node sink) { sink instanceof XxeSink }
17+
18+
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof XxeSanitizer }
19+
20+
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
21+
any(XxeAdditionalTaintStep s).step(n1, n2)
22+
}
23+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/** Provides default definitions to be used in XXE queries. */
2+
3+
import java
4+
private import semmle.code.java.dataflow.TaintTracking2
5+
private import semmle.code.java.security.XmlParsers
6+
import semmle.code.java.security.Xxe
7+
8+
/**
9+
* The default implementation of a XXE sink.
10+
* The argument of a parse call on an insecurely configured XML parser.
11+
*/
12+
private class DefaultXxeSink extends XxeSink {
13+
DefaultXxeSink() {
14+
not exists(SafeSaxSourceFlowConfig safeSource | safeSource.hasFlowTo(this)) and
15+
exists(XmlParserCall parse |
16+
parse.getSink() = this.asExpr() and
17+
not parse.isSafe()
18+
)
19+
}
20+
}
21+
22+
/**
23+
* A taint-tracking configuration for safe XML readers used to parse XML documents.
24+
*/
25+
private class SafeSaxSourceFlowConfig extends TaintTracking2::Configuration {
26+
SafeSaxSourceFlowConfig() { this = "SafeSaxSourceFlowConfig" }
27+
28+
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxSource }
29+
30+
override predicate isSink(DataFlow::Node sink) {
31+
sink.asExpr() = any(XmlParserCall parse).getSink()
32+
}
33+
34+
override int fieldFlowBranchLimit() { result = 0 }
35+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/** Provides taint tracking configurations to be used in remote XXE queries. */
2+
3+
import java
4+
private import semmle.code.java.dataflow.FlowSources
5+
private import semmle.code.java.dataflow.TaintTracking
6+
private import semmle.code.java.security.XxeQuery
7+
8+
/**
9+
* A taint-tracking configuration for unvalidated remote user input that is used in XML external entity expansion.
10+
*/
11+
class XxeConfig extends TaintTracking::Configuration {
12+
XxeConfig() { this = "XxeConfig" }
13+
14+
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
15+
16+
override predicate isSink(DataFlow::Node sink) { sink instanceof XxeSink }
17+
18+
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof XxeSanitizer }
19+
20+
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
21+
any(XxeAdditionalTaintStep s).step(n1, n2)
22+
}
23+
}

java/ql/src/Security/CWE/CWE-611/XXE.ql

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,10 @@
1414
*/
1515

1616
import java
17-
import semmle.code.java.security.XmlParsers
18-
import semmle.code.java.dataflow.FlowSources
19-
import semmle.code.java.dataflow.TaintTracking2
17+
import semmle.code.java.dataflow.DataFlow
18+
import semmle.code.java.security.XxeRemoteQuery
2019
import DataFlow::PathGraph
2120

22-
class SafeSaxSourceFlowConfig extends TaintTracking2::Configuration {
23-
SafeSaxSourceFlowConfig() { this = "XmlParsers::SafeSAXSourceFlowConfig" }
24-
25-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxSource }
26-
27-
override predicate isSink(DataFlow::Node sink) {
28-
sink.asExpr() = any(XmlParserCall parse).getSink()
29-
}
30-
31-
override int fieldFlowBranchLimit() { result = 0 }
32-
}
33-
34-
class UnsafeXxeSink extends DataFlow::ExprNode {
35-
UnsafeXxeSink() {
36-
not exists(SafeSaxSourceFlowConfig safeSource | safeSource.hasFlowTo(this)) and
37-
exists(XmlParserCall parse |
38-
parse.getSink() = this.getExpr() and
39-
not parse.isSafe()
40-
)
41-
}
42-
}
43-
44-
class XxeConfig extends TaintTracking::Configuration {
45-
XxeConfig() { this = "XXE.ql::XxeConfig" }
46-
47-
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
48-
49-
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
50-
}
51-
5221
from DataFlow::PathNode source, DataFlow::PathNode sink, XxeConfig conf
5322
where conf.hasFlowPath(source, sink)
5423
select sink.getNode(), source, sink,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<include src="XXE.qhelp" /></qhelp>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @name Resolving XML external entity in user-controlled data from local source
3+
* @description Parsing user-controlled XML documents and allowing expansion of external entity
4+
* references may lead to disclosure of confidential data or denial of service.
5+
* @kind path-problem
6+
* @problem.severity recommendation
7+
* @security-severity 9.1
8+
* @precision medium
9+
* @id java/xxe-local
10+
* @tags security
11+
* external/cwe/cwe-611
12+
* external/cwe/cwe-776
13+
* external/cwe/cwe-827
14+
*/
15+
16+
import java
17+
import semmle.code.java.dataflow.DataFlow
18+
import semmle.code.java.security.XxeLocalQuery
19+
import DataFlow::PathGraph
20+
21+
from DataFlow::PathNode source, DataFlow::PathNode sink, XxeLocalConfig conf
22+
where conf.hasFlowPath(source, sink)
23+
select sink.getNode(), source, sink,
24+
"XML parsing depends on a $@ without guarding against external entity expansion.",
25+
source.getNode(), "user-provided value"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: newQuery
3+
---
4+
* Added a new query, `java/xxe-local`, which is a version of the XXE query that uses local sources (for example, reads from a local file).

0 commit comments

Comments
 (0)