mirror of
https://github.com/github/codeql.git
synced 2025-12-19 10:23:15 +01:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user