Python: Add XMLVulnerabilityKind

This gives some freedom in changing the name presented, and not worrying about whether you have made a typo that makes everything break :|
This commit is contained in:
Rasmus Wriedt Larsen
2022-03-02 10:58:58 +01:00
parent ee23c05489
commit aaf55b21c4
2 changed files with 47 additions and 21 deletions

View File

@@ -15,6 +15,29 @@ private import semmle.python.dataflow.new.TaintTracking
private import experimental.semmle.python.Frameworks
module XML {
/**
* A kind of XML vulnerability.
*
* See https://pypi.org/project/defusedxml/#python-xml-libraries
*/
class XMLVulnerabilityKind extends string {
XMLVulnerabilityKind() {
this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval",]
}
/** Holds for Billion Laughs vulnerability kind. */
predicate isBillionLaughs() { this = "Billion Laughs" }
/** Holds for Quadratic Blowup vulnerability kind. */
predicate isQuadraticBlowup() { this = "Quadratic Blowup" }
/** Holds for XXE vulnerability kind. */
predicate isXxe() { this = "XXE" }
/** Holds for DTD retrieval vulnerability kind. */
predicate isDtdRetrieval() { this = "DTD retrieval" }
}
/**
* A data-flow node that collects functions parsing XML.
*
@@ -30,7 +53,7 @@ module XML {
/**
* Holds if the parsing method or the parser holding it is vulnerable to `kind`.
*/
predicate vulnerable(string kind) { super.vulnerable(kind) }
predicate vulnerable(XMLVulnerabilityKind kind) { super.vulnerable(kind) }
}
/** Provides classes for modeling XML parsing APIs. */
@@ -50,7 +73,7 @@ module XML {
/**
* Holds if the parsing method or the parser holding it is vulnerable to `kind`.
*/
abstract predicate vulnerable(string kind);
abstract predicate vulnerable(XMLVulnerabilityKind kind);
}
}
@@ -69,7 +92,7 @@ module XML {
/**
* Holds if the parser is vulnerable to `kind`.
*/
predicate vulnerable(string kind) { super.vulnerable(kind) }
predicate vulnerable(XMLVulnerabilityKind kind) { super.vulnerable(kind) }
}
/** Provides classes for modeling XML parsers. */
@@ -89,7 +112,7 @@ module XML {
/**
* Holds if the parser is vulnerable to `kind`.
*/
abstract predicate vulnerable(string kind);
abstract predicate vulnerable(XMLVulnerabilityKind kind);
}
}
}

View File

@@ -24,7 +24,7 @@ private module Xml {
override DataFlow::Node getAnInput() { none() }
override predicate vulnerable(string kind) { none() }
override predicate vulnerable(XML::XMLVulnerabilityKind kind) { none() }
}
/**
@@ -57,7 +57,7 @@ private module Xml {
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override predicate vulnerable(string kind) {
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
exists(XML::XMLParser xmlParser |
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
)
@@ -111,27 +111,27 @@ private module Xml {
override DataFlow::Node getAnInput() { result = this.getAMethodCall("parse").getArg(0) }
override predicate vulnerable(string kind) {
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
exists(DataFlow::MethodCallNode parse, API::Node handler, API::Node feature |
handler = API::moduleImport("xml").getMember("sax").getMember("handler") and
parse.calls(trackSaxFeature(this, feature), "parse") and
parse.getArg(0) = this.getAnInput() // enough to avoid FPs?
|
kind = ["XXE", "DTD retrieval"] and
(kind.isXxe() or kind.isDtdRetrieval()) and
feature = handler.getMember("feature_external_ges")
or
kind = ["Billion Laughs", "Quadratic Blowup"]
(kind.isBillionLaughs() or kind.isQuadraticBlowup())
)
}
predicate vulnerable(DataFlow::Node n, string kind) {
predicate vulnerable(DataFlow::Node n, XML::XMLVulnerabilityKind kind) {
exists(API::Node handler, API::Node feature |
handler = API::moduleImport("xml").getMember("sax").getMember("handler") and
DataFlow::exprNode(trackSaxFeature(this, feature).asExpr())
.(DataFlow::LocalSourceNode)
.flowsTo(n)
|
kind = ["XXE", "DTD retrieval"] and
(kind.isXxe() or kind.isDtdRetrieval()) and
feature = handler.getMember("feature_external_ges")
)
}
@@ -162,14 +162,14 @@ private module Xml {
override DataFlow::Node getAnInput() { none() }
override predicate vulnerable(string kind) {
kind = "XXE" and
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
kind.isXxe() and
not (
exists(this.getArgByName("resolve_entities")) or
this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False f)
)
or
kind = ["Billion Laughs", "Quadratic Blowup"] and
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
(
this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) and
not this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False f)
@@ -206,12 +206,12 @@ private module Xml {
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override predicate vulnerable(string kind) {
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
exists(XML::XMLParser xmlParser |
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
)
or
kind = "XXE" and not exists(this.getArgByName("parser"))
kind.isXxe() and not exists(this.getArgByName("parser"))
}
}
@@ -233,8 +233,8 @@ private module Xml {
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override predicate vulnerable(string kind) {
kind = ["Billion Laughs", "Quadratic Blowup"] and
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f)
}
}
@@ -266,12 +266,13 @@ private module Xml {
override DataFlow::Node getAnInput() { result = this.getArg(0) }
override predicate vulnerable(string kind) {
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
exists(XML::XMLParser xmlParser |
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
)
or
kind = ["Billion Laughs", "Quadratic Blowup"] and not exists(this.getArgByName("parser"))
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
not exists(this.getArgByName("parser"))
}
}
@@ -300,6 +301,8 @@ private module Xml {
result = this.getAMethodCall("register_function").getArg(0)
}
override predicate vulnerable(string kind) { kind = ["Billion Laughs", "Quadratic Blowup"] }
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
kind.isBillionLaughs() or kind.isQuadraticBlowup()
}
}
}