Python: Support feed method of lxml/xml.etree Parsers

This commit is contained in:
Rasmus Wriedt Larsen
2022-03-03 21:26:06 +01:00
parent f72f673e7e
commit 33ebcdf437
3 changed files with 62 additions and 0 deletions

View File

@@ -79,6 +79,28 @@ private module Xml {
}
}
/**
* A call to the `feed` method of an `xml.etree` parser.
*/
private class XMLEtreeParserFeedCall extends DataFlow::CallCfgNode, XML::XMLParsing::Range {
XMLEtreeParserFeedCall() {
this =
API::moduleImport("xml")
.getMember("etree")
.getMember("ElementTree")
.getMember("XMLParser")
.getReturn()
.getMember("feed")
.getACall()
}
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
kind.isBillionLaughs() or kind.isQuadraticBlowup()
}
}
/**
* A call to the `setFeature` method on a XML sax parser.
*
@@ -322,6 +344,7 @@ private module Xml {
}
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
// TODO: This should be done with type-tracking
exists(XML::XMLParser xmlParser |
xmlParser = this.getArgByName("parser").getALocalSource() and xmlParser.vulnerable(kind)
)
@@ -330,6 +353,33 @@ private module Xml {
}
}
/**
* A call to the `feed` method of an `lxml.etree` parser.
*/
private class LXMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range {
LXMLEtreeParserFeedCall() {
exists(API::Node parserInstance |
parserInstance =
API::moduleImport("lxml").getMember("etree").getMember("XMLParser").getReturn()
or
parserInstance =
API::moduleImport("lxml").getMember("etree").getMember("get_default_parser").getReturn()
|
this = parserInstance.getMember("feed").getACall()
)
}
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
// TODO: This should be done with type-tracking
exists(XML::XMLParser xmlParser |
xmlParser = this.getObject().getALocalSource() and
xmlParser.vulnerable(kind)
)
}
}
/**
* Gets a call to `xmltodict.parse`.
*

View File

@@ -26,6 +26,12 @@ lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='XXE'
parser = lxml.etree.get_default_parser()
lxml.etree.fromstring(x, parser=parser) # $ input=x vuln='XXE'
# manual use of feed method
parser = lxml.etree.XMLParser()
parser.feed(x) # $ input=x vuln='XXE'
parser.feed(data=x) # $ input=x vuln='XXE'
parser.close()
# XXE-safe
parser = lxml.etree.XMLParser(resolve_entities=False)
lxml.etree.fromstring(x, parser=parser) # $ input=x

View File

@@ -27,6 +27,12 @@ xml.etree.ElementTree.iterparse(source=StringIO(x)) # $ input=StringIO(..) vuln=
parser = xml.etree.ElementTree.XMLParser()
xml.etree.ElementTree.fromstring(x, parser=parser) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup'
# manual use of feed method
parser = xml.etree.ElementTree.XMLParser()
parser.feed(x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup'
parser.feed(data=x) # $ input=x vuln='Billion Laughs' vuln='Quadratic Blowup'
parser.close()
# note: it's technically possible to use the thing wrapper func `fromstring` with an
# `lxml` parser, and thereby change what vulnerabilities you are exposed to.. but it
# seems very unlikely that anyone would do this, so we have intentionally not added any