Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aaf55b2

Browse files
committed
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 :|
1 parent ee23c05 commit aaf55b2

2 files changed

Lines changed: 47 additions & 21 deletions

File tree

python/ql/src/experimental/semmle/python/Concepts.qll

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,29 @@ private import semmle.python.dataflow.new.TaintTracking
1515
private import experimental.semmle.python.Frameworks
1616

1717
module XML {
18+
/**
19+
* A kind of XML vulnerability.
20+
*
21+
* See https://pypi.org/project/defusedxml/#python-xml-libraries
22+
*/
23+
class XMLVulnerabilityKind extends string {
24+
XMLVulnerabilityKind() {
25+
this in ["Billion Laughs", "Quadratic Blowup", "XXE", "DTD retrieval",]
26+
}
27+
28+
/** Holds for Billion Laughs vulnerability kind. */
29+
predicate isBillionLaughs() { this = "Billion Laughs" }
30+
31+
/** Holds for Quadratic Blowup vulnerability kind. */
32+
predicate isQuadraticBlowup() { this = "Quadratic Blowup" }
33+
34+
/** Holds for XXE vulnerability kind. */
35+
predicate isXxe() { this = "XXE" }
36+
37+
/** Holds for DTD retrieval vulnerability kind. */
38+
predicate isDtdRetrieval() { this = "DTD retrieval" }
39+
}
40+
1841
/**
1942
* A data-flow node that collects functions parsing XML.
2043
*
@@ -30,7 +53,7 @@ module XML {
3053
/**
3154
* Holds if the parsing method or the parser holding it is vulnerable to `kind`.
3255
*/
33-
predicate vulnerable(string kind) { super.vulnerable(kind) }
56+
predicate vulnerable(XMLVulnerabilityKind kind) { super.vulnerable(kind) }
3457
}
3558

3659
/** Provides classes for modeling XML parsing APIs. */
@@ -50,7 +73,7 @@ module XML {
5073
/**
5174
* Holds if the parsing method or the parser holding it is vulnerable to `kind`.
5275
*/
53-
abstract predicate vulnerable(string kind);
76+
abstract predicate vulnerable(XMLVulnerabilityKind kind);
5477
}
5578
}
5679

@@ -69,7 +92,7 @@ module XML {
6992
/**
7093
* Holds if the parser is vulnerable to `kind`.
7194
*/
72-
predicate vulnerable(string kind) { super.vulnerable(kind) }
95+
predicate vulnerable(XMLVulnerabilityKind kind) { super.vulnerable(kind) }
7396
}
7497

7598
/** Provides classes for modeling XML parsers. */
@@ -89,7 +112,7 @@ module XML {
89112
/**
90113
* Holds if the parser is vulnerable to `kind`.
91114
*/
92-
abstract predicate vulnerable(string kind);
115+
abstract predicate vulnerable(XMLVulnerabilityKind kind);
93116
}
94117
}
95118
}

python/ql/src/experimental/semmle/python/frameworks/Xml.qll

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private module Xml {
2424

2525
override DataFlow::Node getAnInput() { none() }
2626

27-
override predicate vulnerable(string kind) { none() }
27+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) { none() }
2828
}
2929

3030
/**
@@ -57,7 +57,7 @@ private module Xml {
5757

5858
override DataFlow::Node getAnInput() { result = this.getArg(0) }
5959

60-
override predicate vulnerable(string kind) {
60+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
6161
exists(XML::XMLParser xmlParser |
6262
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
6363
)
@@ -111,27 +111,27 @@ private module Xml {
111111

112112
override DataFlow::Node getAnInput() { result = this.getAMethodCall("parse").getArg(0) }
113113

114-
override predicate vulnerable(string kind) {
114+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
115115
exists(DataFlow::MethodCallNode parse, API::Node handler, API::Node feature |
116116
handler = API::moduleImport("xml").getMember("sax").getMember("handler") and
117117
parse.calls(trackSaxFeature(this, feature), "parse") and
118118
parse.getArg(0) = this.getAnInput() // enough to avoid FPs?
119119
|
120-
kind = ["XXE", "DTD retrieval"] and
120+
(kind.isXxe() or kind.isDtdRetrieval()) and
121121
feature = handler.getMember("feature_external_ges")
122122
or
123-
kind = ["Billion Laughs", "Quadratic Blowup"]
123+
(kind.isBillionLaughs() or kind.isQuadraticBlowup())
124124
)
125125
}
126126

127-
predicate vulnerable(DataFlow::Node n, string kind) {
127+
predicate vulnerable(DataFlow::Node n, XML::XMLVulnerabilityKind kind) {
128128
exists(API::Node handler, API::Node feature |
129129
handler = API::moduleImport("xml").getMember("sax").getMember("handler") and
130130
DataFlow::exprNode(trackSaxFeature(this, feature).asExpr())
131131
.(DataFlow::LocalSourceNode)
132132
.flowsTo(n)
133133
|
134-
kind = ["XXE", "DTD retrieval"] and
134+
(kind.isXxe() or kind.isDtdRetrieval()) and
135135
feature = handler.getMember("feature_external_ges")
136136
)
137137
}
@@ -162,14 +162,14 @@ private module Xml {
162162

163163
override DataFlow::Node getAnInput() { none() }
164164

165-
override predicate vulnerable(string kind) {
166-
kind = "XXE" and
165+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
166+
kind.isXxe() and
167167
not (
168168
exists(this.getArgByName("resolve_entities")) or
169169
this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False f)
170170
)
171171
or
172-
kind = ["Billion Laughs", "Quadratic Blowup"] and
172+
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
173173
(
174174
this.getArgByName("huge_tree").getALocalSource().asExpr() = any(True t) and
175175
not this.getArgByName("resolve_entities").getALocalSource().asExpr() = any(False f)
@@ -206,12 +206,12 @@ private module Xml {
206206

207207
override DataFlow::Node getAnInput() { result = this.getArg(0) }
208208

209-
override predicate vulnerable(string kind) {
209+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
210210
exists(XML::XMLParser xmlParser |
211211
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
212212
)
213213
or
214-
kind = "XXE" and not exists(this.getArgByName("parser"))
214+
kind.isXxe() and not exists(this.getArgByName("parser"))
215215
}
216216
}
217217

@@ -233,8 +233,8 @@ private module Xml {
233233

234234
override DataFlow::Node getAnInput() { result = this.getArg(0) }
235235

236-
override predicate vulnerable(string kind) {
237-
kind = ["Billion Laughs", "Quadratic Blowup"] and
236+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
237+
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
238238
this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f)
239239
}
240240
}
@@ -266,12 +266,13 @@ private module Xml {
266266

267267
override DataFlow::Node getAnInput() { result = this.getArg(0) }
268268

269-
override predicate vulnerable(string kind) {
269+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
270270
exists(XML::XMLParser xmlParser |
271271
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
272272
)
273273
or
274-
kind = ["Billion Laughs", "Quadratic Blowup"] and not exists(this.getArgByName("parser"))
274+
(kind.isBillionLaughs() or kind.isQuadraticBlowup()) and
275+
not exists(this.getArgByName("parser"))
275276
}
276277
}
277278

@@ -300,6 +301,8 @@ private module Xml {
300301
result = this.getAMethodCall("register_function").getArg(0)
301302
}
302303

303-
override predicate vulnerable(string kind) { kind = ["Billion Laughs", "Quadratic Blowup"] }
304+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
305+
kind.isBillionLaughs() or kind.isQuadraticBlowup()
306+
}
304307
}
305308
}

0 commit comments

Comments
 (0)