diff options
-rw-r--r-- | defusedxml/ElementTree.py | 54 | ||||
-rw-r--r-- | defusedxml/__init__.py | 31 | ||||
-rw-r--r-- | defusedxml/cElementTree.py | 19 | ||||
-rw-r--r-- | defusedxml/common.py | 51 | ||||
-rw-r--r-- | defusedxml/expatbuilder.py | 47 | ||||
-rw-r--r-- | defusedxml/expatreader.py | 28 | ||||
-rw-r--r-- | defusedxml/lxml.py | 34 | ||||
-rw-r--r-- | defusedxml/minidom.py | 57 | ||||
-rw-r--r-- | defusedxml/pulldom.py | 15 | ||||
-rw-r--r-- | defusedxml/sax.py | 21 | ||||
-rw-r--r-- | defusedxml/xmlrpc.py | 22 | ||||
-rwxr-xr-x | other/exploit_webdav.py | 8 | ||||
-rwxr-xr-x | other/exploit_xmlrpc.py | 2 | ||||
-rwxr-xr-x | other/python_external.py | 6 | ||||
-rwxr-xr-x | other/python_genshi.py | 1 | ||||
-rw-r--r-- | tests.py | 131 |
16 files changed, 294 insertions, 233 deletions
diff --git a/defusedxml/ElementTree.py b/defusedxml/ElementTree.py index 80da8b4..f9e2032 100644 --- a/defusedxml/ElementTree.py +++ b/defusedxml/ElementTree.py @@ -23,8 +23,12 @@ else: from xml.etree.ElementTree import ParseError -from .common import (DTDForbidden, EntitiesForbidden, - ExternalReferenceForbidden, _generate_etree_functions) +from .common import ( + DTDForbidden, + EntitiesForbidden, + ExternalReferenceForbidden, + _generate_etree_functions, +) __origin__ = "xml.etree.ElementTree" @@ -62,10 +66,15 @@ _sentinel = object() class DefusedXMLParser(_XMLParser): - - def __init__(self, html=_sentinel, target=None, encoding=None, - forbid_dtd=False, forbid_entities=True, - forbid_external=True): + def __init__( + self, + html=_sentinel, + target=None, + encoding=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): # Python 2.x old style class _XMLParser.__init__(self, target=target, encoding=encoding) if html is not _sentinel: @@ -77,7 +86,7 @@ class DefusedXMLParser(_XMLParser): warnings.warn( "'html' keyword argument is no longer supported. Pass " "in arguments as keyword arguments.", - category=DeprecationWarning + category=DeprecationWarning, ) self.forbid_dtd = forbid_dtd @@ -95,21 +104,19 @@ class DefusedXMLParser(_XMLParser): if self.forbid_external: parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler - def defused_start_doctype_decl(self, name, sysid, pubid, - has_internal_subset): + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): raise DTDForbidden(name, sysid, pubid) - def defused_entity_decl(self, name, is_parameter_entity, value, base, - sysid, pubid, notation_name): + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, - notation_name): + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): # expat 1.2 raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) - def defused_external_entity_ref_handler(self, context, base, sysid, - pubid): + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): raise ExternalReferenceForbidden(context, base, sysid, pubid) @@ -117,13 +124,20 @@ class DefusedXMLParser(_XMLParser): # XMLParse is a typo, keep it for backwards compatibility XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser -parse, iterparse, fromstring = _generate_etree_functions(DefusedXMLParser, - _TreeBuilder, _parse, - _iterparse) +parse, iterparse, fromstring = _generate_etree_functions( + DefusedXMLParser, _TreeBuilder, _parse, _iterparse +) XML = fromstring __all__ = [ - 'ParseError', 'XML', 'XMLParse', 'XMLParser', 'XMLTreeBuilder', - 'fromstring', 'iterparse', 'parse', 'tostring' + "ParseError", + "XML", + "XMLParse", + "XMLParser", + "XMLTreeBuilder", + "fromstring", + "iterparse", + "parse", + "tostring", ] diff --git a/defusedxml/__init__.py b/defusedxml/__init__.py index e96d6e7..c6874d7 100644 --- a/defusedxml/__init__.py +++ b/defusedxml/__init__.py @@ -7,9 +7,14 @@ """ from __future__ import print_function, absolute_import -from .common import (DefusedXmlException, DTDForbidden, EntitiesForbidden, - ExternalReferenceForbidden, NotSupportedError, - _apply_defusing) +from .common import ( + DefusedXmlException, + DTDForbidden, + EntitiesForbidden, + ExternalReferenceForbidden, + NotSupportedError, + _apply_defusing, +) def defuse_stdlib(): @@ -31,8 +36,15 @@ def defuse_stdlib(): xmlrpc.monkey_patch() defused[xmlrpc] = None - for defused_mod in [cElementTree, ElementTree, minidom, pulldom, sax, - expatbuilder, expatreader]: + for defused_mod in [ + cElementTree, + ElementTree, + minidom, + pulldom, + sax, + expatbuilder, + expatreader, + ]: stdlib_mod = _apply_defusing(defused_mod) defused[defused_mod] = stdlib_mod @@ -41,5 +53,10 @@ def defuse_stdlib(): __version__ = "0.6.0.dev1" -__all__ = ['DefusedXmlException', 'DTDForbidden', 'EntitiesForbidden', - 'ExternalReferenceForbidden', 'NotSupportedError'] +__all__ = [ + "DefusedXmlException", + "DTDForbidden", + "EntitiesForbidden", + "ExternalReferenceForbidden", + "NotSupportedError", +] diff --git a/defusedxml/cElementTree.py b/defusedxml/cElementTree.py index 61cb38f..fdc761e 100644 --- a/defusedxml/cElementTree.py +++ b/defusedxml/cElementTree.py @@ -10,6 +10,7 @@ from __future__ import absolute_import from xml.etree.cElementTree import TreeBuilder as _TreeBuilder from xml.etree.cElementTree import parse as _parse from xml.etree.cElementTree import tostring + # iterparse from ElementTree! from xml.etree.ElementTree import iterparse as _iterparse @@ -22,10 +23,18 @@ __origin__ = "xml.etree.cElementTree" # XMLParse is a typo, keep it for backwards compatibility XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser -parse, iterparse, fromstring = _generate_etree_functions(DefusedXMLParser, - _TreeBuilder, _parse, - _iterparse) +parse, iterparse, fromstring = _generate_etree_functions( + DefusedXMLParser, _TreeBuilder, _parse, _iterparse +) XML = fromstring -__all__ = ['XML', 'XMLParse', 'XMLParser', 'XMLTreeBuilder', 'fromstring', - 'iterparse', 'parse', 'tostring'] +__all__ = [ + "XML", + "XMLParse", + "XMLParser", + "XMLTreeBuilder", + "fromstring", + "iterparse", + "parse", + "tostring", +] diff --git a/defusedxml/common.py b/defusedxml/common.py index 1995d61..9dcdc5a 100644 --- a/defusedxml/common.py +++ b/defusedxml/common.py @@ -12,7 +12,7 @@ PY3 = sys.version_info[0] == 3 # Fail early when pyexpat is not installed correctly if not hasattr(xml.parsers.expat, "ParserCreate"): - raise ImportError('pyexpat') + raise ImportError("pyexpat") class DefusedXmlException(ValueError): @@ -90,35 +90,44 @@ def _apply_defusing(defused_mod): return stdlib_mod -def _generate_etree_functions(DefusedXMLParser, _TreeBuilder, - _parse, _iterparse): +def _generate_etree_functions(DefusedXMLParser, _TreeBuilder, _parse, _iterparse): """Factory for functions needed by etree, dependent on whether cElementTree or ElementTree is used.""" - def parse(source, parser=None, forbid_dtd=False, forbid_entities=True, - forbid_external=True): + def parse(source, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True): if parser is None: - parser = DefusedXMLParser(target=_TreeBuilder(), - forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) return _parse(source, parser) - def iterparse(source, events=None, parser=None, forbid_dtd=False, - forbid_entities=True, forbid_external=True): + def iterparse( + source, + events=None, + parser=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): if parser is None: - parser = DefusedXMLParser(target=_TreeBuilder(), - forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) return _iterparse(source, events, parser) - def fromstring(text, forbid_dtd=False, forbid_entities=True, - forbid_external=True): - parser = DefusedXMLParser(target=_TreeBuilder(), - forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + def fromstring(text, forbid_dtd=False, forbid_entities=True, forbid_external=True): + parser = DefusedXMLParser( + target=_TreeBuilder(), + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) parser.feed(text) return parser.close() diff --git a/defusedxml/expatbuilder.py b/defusedxml/expatbuilder.py index ffe4f7d..ab743d2 100644 --- a/defusedxml/expatbuilder.py +++ b/defusedxml/expatbuilder.py @@ -10,8 +10,7 @@ from __future__ import print_function, absolute_import from xml.dom.expatbuilder import ExpatBuilder as _ExpatBuilder from xml.dom.expatbuilder import Namespaces as _Namespaces -from .common import (DTDForbidden, EntitiesForbidden, - ExternalReferenceForbidden) +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden __origin__ = "xml.dom.expatbuilder" @@ -19,28 +18,27 @@ __origin__ = "xml.dom.expatbuilder" class DefusedExpatBuilder(_ExpatBuilder): """Defused document builder""" - def __init__(self, options=None, forbid_dtd=False, forbid_entities=True, - forbid_external=True): + def __init__( + self, options=None, forbid_dtd=False, forbid_entities=True, forbid_external=True + ): _ExpatBuilder.__init__(self, options) self.forbid_dtd = forbid_dtd self.forbid_entities = forbid_entities self.forbid_external = forbid_external - def defused_start_doctype_decl(self, name, sysid, pubid, - has_internal_subset): + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): raise DTDForbidden(name, sysid, pubid) - def defused_entity_decl(self, name, is_parameter_entity, value, base, - sysid, pubid, notation_name): + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, - notation_name): + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): # expat 1.2 raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) - def defused_external_entity_ref_handler(self, context, base, sysid, - pubid): + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): raise ExternalReferenceForbidden(context, base, sysid, pubid) def install(self, parser): @@ -62,16 +60,14 @@ class DefusedExpatBuilderNS(_Namespaces, DefusedExpatBuilder): def install(self, parser): DefusedExpatBuilder.install(self, parser) if self._options.namespace_declarations: - parser.StartNamespaceDeclHandler = ( - self.start_namespace_decl_handler) + parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler def reset(self): DefusedExpatBuilder.reset(self) self._initNamespaces() -def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, - forbid_external=True): +def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True): """Parse a document, returning the resulting Document node. 'file' may be either a file name or an open file object. @@ -80,12 +76,12 @@ def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, build_builder = DefusedExpatBuilderNS else: build_builder = DefusedExpatBuilder - builder = build_builder(forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + builder = build_builder( + forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external + ) if isinstance(file, str): - fp = open(file, 'rb') + fp = open(file, "rb") try: result = builder.parseFile(fp) finally: @@ -95,8 +91,9 @@ def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, return result -def parseString(string, namespaces=True, forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parseString( + string, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True +): """Parse a document from a string, returning the resulting Document node. """ @@ -104,7 +101,7 @@ def parseString(string, namespaces=True, forbid_dtd=False, build_builder = DefusedExpatBuilderNS else: build_builder = DefusedExpatBuilder - builder = build_builder(forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + builder = build_builder( + forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external + ) return builder.parseString(string) diff --git a/defusedxml/expatreader.py b/defusedxml/expatreader.py index f2ec286..198588f 100644 --- a/defusedxml/expatreader.py +++ b/defusedxml/expatreader.py @@ -9,8 +9,7 @@ from __future__ import print_function, absolute_import from xml.sax.expatreader import ExpatParser as _ExpatParser -from .common import (DTDForbidden, EntitiesForbidden, - ExternalReferenceForbidden) +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden __origin__ = "xml.sax.expatreader" @@ -18,29 +17,32 @@ __origin__ = "xml.sax.expatreader" class DefusedExpatParser(_ExpatParser): """Defused SAX driver for the pyexpat C module.""" - def __init__(self, namespaceHandling=0, bufsize=2 ** 16 - 20, - forbid_dtd=False, forbid_entities=True, - forbid_external=True): + def __init__( + self, + namespaceHandling=0, + bufsize=2 ** 16 - 20, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, + ): _ExpatParser.__init__(self, namespaceHandling, bufsize) self.forbid_dtd = forbid_dtd self.forbid_entities = forbid_entities self.forbid_external = forbid_external - def defused_start_doctype_decl(self, name, sysid, pubid, - has_internal_subset): + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): raise DTDForbidden(name, sysid, pubid) - def defused_entity_decl(self, name, is_parameter_entity, value, base, - sysid, pubid, notation_name): + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, - notation_name): + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): # expat 1.2 raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) - def defused_external_entity_ref_handler(self, context, base, sysid, - pubid): + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): raise ExternalReferenceForbidden(context, base, sysid, pubid) def reset(self): diff --git a/defusedxml/lxml.py b/defusedxml/lxml.py index 6d31f63..1320ca5 100644 --- a/defusedxml/lxml.py +++ b/defusedxml/lxml.py @@ -24,16 +24,16 @@ tostring = _etree.tostring warnings.warn( - "defusedxml.lxml is no longer supported and will be removed in a " - "future release.", + "defusedxml.lxml is no longer supported and will be removed in a " "future release.", category=DeprecationWarning, - stacklevel=2 + stacklevel=2, ) class RestrictedElement(_etree.ElementBase): """A restricted Element class that filters out instances of some classes """ + __slots__ = () # blacklist = (etree._Entity, etree._ProcessingInstruction, etree._Comment) blacklist = _etree._Entity @@ -50,8 +50,7 @@ class RestrictedElement(_etree.ElementBase): return self._filter(iterator) def iterchildren(self, tag=None, reversed=False): - iterator = super(RestrictedElement, self).iterchildren( - tag=tag, reversed=reversed) + iterator = super(RestrictedElement, self).iterchildren(tag=tag, reversed=reversed) return self._filter(iterator) def iter(self, tag=None, *tags): @@ -59,13 +58,11 @@ class RestrictedElement(_etree.ElementBase): return self._filter(iterator) def iterdescendants(self, tag=None, *tags): - iterator = super(RestrictedElement, - self).iterdescendants(tag=tag, *tags) + iterator = super(RestrictedElement, self).iterdescendants(tag=tag, *tags) return self._filter(iterator) def itersiblings(self, tag=None, preceding=False): - iterator = super(RestrictedElement, self).itersiblings( - tag=tag, preceding=preceding) + iterator = super(RestrictedElement, self).itersiblings(tag=tag, preceding=preceding) return self._filter(iterator) def getchildren(self): @@ -80,8 +77,9 @@ class RestrictedElement(_etree.ElementBase): class GlobalParserTLS(threading.local): """Thread local context for custom parser instances """ + parser_config = { - 'resolve_entities': False, + "resolve_entities": False, # 'remove_comments': True, # 'remove_pis': True, } @@ -120,25 +118,20 @@ def check_docinfo(elementtree, forbid_dtd=False, forbid_entities=True): docinfo = elementtree.docinfo if docinfo.doctype: if forbid_dtd: - raise DTDForbidden(docinfo.doctype, - docinfo.system_url, - docinfo.public_id) + raise DTDForbidden(docinfo.doctype, docinfo.system_url, docinfo.public_id) if forbid_entities and not LXML3: # lxml < 3 has no iterentities() - raise NotSupportedError("Unable to check for entity declarations " - "in lxml 2.x") + raise NotSupportedError("Unable to check for entity declarations " "in lxml 2.x") if forbid_entities: for dtd in docinfo.internalDTD, docinfo.externalDTD: if dtd is None: continue for entity in dtd.iterentities(): - raise EntitiesForbidden(entity.name, entity.content, None, - None, None, None) + raise EntitiesForbidden(entity.name, entity.content, None, None, None, None) -def parse(source, parser=None, base_url=None, forbid_dtd=False, - forbid_entities=True): +def parse(source, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True): if parser is None: parser = getDefaultParser() elementtree = _etree.parse(source, parser, base_url=base_url) @@ -146,8 +139,7 @@ def parse(source, parser=None, base_url=None, forbid_dtd=False, return elementtree -def fromstring(text, parser=None, base_url=None, forbid_dtd=False, - forbid_entities=True): +def fromstring(text, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True): if parser is None: parser = getDefaultParser() rootelement = _etree.fromstring(text, parser, base_url=base_url) diff --git a/defusedxml/minidom.py b/defusedxml/minidom.py index eea895c..78033b6 100644 --- a/defusedxml/minidom.py +++ b/defusedxml/minidom.py @@ -14,29 +14,50 @@ from . import pulldom as _pulldom __origin__ = "xml.dom.minidom" -def parse(file, parser=None, bufsize=None, forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parse( + file, parser=None, bufsize=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): """Parse a file into a DOM by filename or file object.""" if parser is None and not bufsize: - return _expatbuilder.parse(file, forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + return _expatbuilder.parse( + file, + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) else: - return _do_pulldom_parse(_pulldom.parse, (file,), - {'parser': parser, 'bufsize': bufsize, - 'forbid_dtd': forbid_dtd, 'forbid_entities': forbid_entities, - 'forbid_external': forbid_external}) + return _do_pulldom_parse( + _pulldom.parse, + (file,), + { + "parser": parser, + "bufsize": bufsize, + "forbid_dtd": forbid_dtd, + "forbid_entities": forbid_entities, + "forbid_external": forbid_external, + }, + ) -def parseString(string, parser=None, forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parseString( + string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): """Parse a file into a DOM from a string.""" if parser is None: - return _expatbuilder.parseString(string, forbid_dtd=forbid_dtd, - forbid_entities=forbid_entities, - forbid_external=forbid_external) + return _expatbuilder.parseString( + string, + forbid_dtd=forbid_dtd, + forbid_entities=forbid_entities, + forbid_external=forbid_external, + ) else: - return _do_pulldom_parse(_pulldom.parseString, (string,), - {'parser': parser, 'forbid_dtd': forbid_dtd, - 'forbid_entities': forbid_entities, - 'forbid_external': forbid_external}) + return _do_pulldom_parse( + _pulldom.parseString, + (string,), + { + "parser": parser, + "forbid_dtd": forbid_dtd, + "forbid_entities": forbid_entities, + "forbid_external": forbid_external, + }, + ) diff --git a/defusedxml/pulldom.py b/defusedxml/pulldom.py index e2c846a..e3b10a4 100644 --- a/defusedxml/pulldom.py +++ b/defusedxml/pulldom.py @@ -14,8 +14,14 @@ from .sax import make_parser __origin__ = "xml.dom.pulldom" -def parse(stream_or_string, parser=None, bufsize=None, forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parse( + stream_or_string, + parser=None, + bufsize=None, + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): if parser is None: parser = make_parser() parser.forbid_dtd = forbid_dtd @@ -24,8 +30,9 @@ def parse(stream_or_string, parser=None, bufsize=None, forbid_dtd=False, return _parse(stream_or_string, parser, bufsize) -def parseString(string, parser=None, forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parseString( + string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True +): if parser is None: parser = make_parser() parser.forbid_dtd = forbid_dtd diff --git a/defusedxml/sax.py b/defusedxml/sax.py index 77aebc5..b2786f7 100644 --- a/defusedxml/sax.py +++ b/defusedxml/sax.py @@ -15,8 +15,14 @@ from . import expatreader __origin__ = "xml.sax" -def parse(source, handler, errorHandler=_ErrorHandler(), forbid_dtd=False, - forbid_entities=True, forbid_external=True): +def parse( + source, + handler, + errorHandler=_ErrorHandler(), + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): parser = make_parser() parser.setContentHandler(handler) parser.setErrorHandler(errorHandler) @@ -26,9 +32,14 @@ def parse(source, handler, errorHandler=_ErrorHandler(), forbid_dtd=False, parser.parse(source) -def parseString(string, handler, errorHandler=_ErrorHandler(), - forbid_dtd=False, forbid_entities=True, - forbid_external=True): +def parseString( + string, + handler, + errorHandler=_ErrorHandler(), + forbid_dtd=False, + forbid_entities=True, + forbid_external=True, +): from io import BytesIO if errorHandler is None: diff --git a/defusedxml/xmlrpc.py b/defusedxml/xmlrpc.py index 5572c6b..3569167 100644 --- a/defusedxml/xmlrpc.py +++ b/defusedxml/xmlrpc.py @@ -11,8 +11,7 @@ from __future__ import print_function, absolute_import import io -from .common import ( - DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden, PY3) +from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden, PY3 if PY3: __origin__ = "xmlrpc.client" @@ -25,6 +24,7 @@ else: __origin__ = "xmlrpclib" from xmlrpclib import ExpatParser import xmlrpclib as xmlrpc_client + xmlrpc_server = None from xmlrpclib import gzip_decode as _orig_gzip_decode from xmlrpclib import GzipDecodedResponse as _OrigGzipDecodedResponse @@ -107,9 +107,7 @@ class DefusedGzipDecodedResponse(gzip.GzipFile if gzip else object): class DefusedExpatParser(ExpatParser): - - def __init__(self, target, forbid_dtd=False, forbid_entities=True, - forbid_external=True): + def __init__(self, target, forbid_dtd=False, forbid_entities=True, forbid_external=True): ExpatParser.__init__(self, target) self.forbid_dtd = forbid_dtd self.forbid_entities = forbid_entities @@ -123,21 +121,19 @@ class DefusedExpatParser(ExpatParser): if self.forbid_external: parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler - def defused_start_doctype_decl(self, name, sysid, pubid, - has_internal_subset): + def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset): raise DTDForbidden(name, sysid, pubid) - def defused_entity_decl(self, name, is_parameter_entity, value, base, - sysid, pubid, notation_name): + def defused_entity_decl( + self, name, is_parameter_entity, value, base, sysid, pubid, notation_name + ): raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name) - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, - notation_name): + def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): # expat 1.2 raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) - def defused_external_entity_ref_handler(self, context, base, sysid, - pubid): + def defused_external_entity_ref_handler(self, context, base, sysid, pubid): raise ExternalReferenceForbidden(context, base, sysid, pubid) diff --git a/other/exploit_webdav.py b/other/exploit_webdav.py index 3288c28..1035139 100755 --- a/other/exploit_webdav.py +++ b/other/exploit_webdav.py @@ -3,6 +3,8 @@ Author: Christian Heimes """ +from __future__ import print_function + import sys import base64 import urlparse @@ -28,11 +30,7 @@ xml = """<?xml version='1.0'?> xml = xml.replace("VALUE", "a" * 30000) xml = xml.replace("QUAD", "&a;" * 1000) -headers = { - "Content-Type": "text/xml", - "Content-Length": len(xml), - "Depth": 1, - } +headers = {"Content-Type": "text/xml", "Content-Length": len(xml), "Depth": 1} if url.username: auth = base64.b64encode(":".join((url.username, url.password))) diff --git a/other/exploit_xmlrpc.py b/other/exploit_xmlrpc.py index da8e8d0..06147c2 100755 --- a/other/exploit_xmlrpc.py +++ b/other/exploit_xmlrpc.py @@ -3,6 +3,8 @@ Author: Christian Heimes """ +from __future__ import print_function + import sys import urllib2 diff --git a/other/python_external.py b/other/python_external.py index 7c5ab0c..2926c67 100755 --- a/other/python_external.py +++ b/other/python_external.py @@ -3,7 +3,8 @@ Author: Christian Heimes """ -import sys +from __future__ import print_function + from xml.sax import ContentHandler from xml.sax import parseString @@ -41,7 +42,7 @@ class WeatherHandler(ContentHandler): def characters(self, content): if self.tag == "processing": - self.city.append(content) + self.city.append(content) def weatherResponse(xml): @@ -52,6 +53,7 @@ def weatherResponse(xml): else: return "<error>Unknown city %s</error>" % handler.city[:500] + for xml in (xml_good, xml_bad_file, xml_bad_url): print("\nREQUEST:\n--------") print(xml) diff --git a/other/python_genshi.py b/other/python_genshi.py index 183d1fe..cccc98e 100755 --- a/other/python_genshi.py +++ b/other/python_genshi.py @@ -6,4 +6,3 @@ from genshi.input import XMLParser with open(sys.argv[1]) as f: parser = XMLParser(f) pprint(list(parser)) - @@ -12,8 +12,12 @@ from pyexpat import ExpatError from defusedxml import cElementTree, ElementTree, minidom, pulldom, sax, xmlrpc from defusedxml import defuse_stdlib -from defusedxml import (DTDForbidden, EntitiesForbidden, - ExternalReferenceForbidden, NotSupportedError) +from defusedxml import ( + DTDForbidden, + EntitiesForbidden, + ExternalReferenceForbidden, + NotSupportedError, +) from defusedxml.common import PY3 @@ -24,16 +28,14 @@ except ImportError: if sys.version_info < (3, 7): - warnings.filterwarnings( - 'once', - category=DeprecationWarning - ) + warnings.filterwarnings("once", category=DeprecationWarning) try: with warnings.catch_warnings(record=True) as lxml_warnings: from defusedxml import lxml from lxml.etree import XMLSyntaxError + LXML3 = lxml.LXML3 except ImportError: lxml = None @@ -42,11 +44,7 @@ except ImportError: lxml_warnings = None -warnings.filterwarnings( - 'error', - category=DeprecationWarning, - module=r"defusedxml\..*" -) +warnings.filterwarnings("error", category=DeprecationWarning, module=r"defusedxml\..*") HERE = os.path.dirname(os.path.abspath(__file__)) @@ -107,68 +105,57 @@ class BaseTests(DefusedTestCase): self.assertRaises(EntitiesForbidden, self.parse, self.xml_quadratic) self.assertRaises(EntitiesForbidden, self.parse, self.xml_external) - self.assertRaises(EntitiesForbidden, self.parseString, - self.get_content(self.xml_bomb)) - self.assertRaises(EntitiesForbidden, self.parseString, - self.get_content(self.xml_quadratic)) - self.assertRaises(EntitiesForbidden, self.parseString, - self.get_content(self.xml_external)) + self.assertRaises(EntitiesForbidden, self.parseString, self.get_content(self.xml_bomb)) + self.assertRaises( + EntitiesForbidden, self.parseString, self.get_content(self.xml_quadratic) + ) + self.assertRaises( + EntitiesForbidden, self.parseString, self.get_content(self.xml_external) + ) if self.iterparse: - self.assertRaises(EntitiesForbidden, self.iterparse, - self.xml_bomb) - self.assertRaises(EntitiesForbidden, self.iterparse, - self.xml_quadratic) - self.assertRaises(EntitiesForbidden, self.iterparse, - self.xml_external) + self.assertRaises(EntitiesForbidden, self.iterparse, self.xml_bomb) + self.assertRaises(EntitiesForbidden, self.iterparse, self.xml_quadratic) + self.assertRaises(EntitiesForbidden, self.iterparse, self.xml_external) def test_entity_cycle(self): - self.assertRaises(self.cyclic_error, self.parse, self.xml_cyclic, - forbid_entities=False) + self.assertRaises(self.cyclic_error, self.parse, self.xml_cyclic, forbid_entities=False) def test_dtd_forbidden(self): - self.assertRaises(DTDForbidden, self.parse, self.xml_bomb, - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parse, self.xml_quadratic, - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parse, self.xml_external, - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parse, self.xml_dtd, - forbid_dtd=True) - - self.assertRaises(DTDForbidden, self.parseString, - self.get_content(self.xml_bomb), - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parseString, - self.get_content(self.xml_quadratic), - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parseString, - self.get_content(self.xml_external), - forbid_dtd=True) - self.assertRaises(DTDForbidden, self.parseString, - self.get_content(self.xml_dtd), - forbid_dtd=True) + self.assertRaises(DTDForbidden, self.parse, self.xml_bomb, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.parse, self.xml_quadratic, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.parse, self.xml_external, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.parse, self.xml_dtd, forbid_dtd=True) + + self.assertRaises( + DTDForbidden, self.parseString, self.get_content(self.xml_bomb), forbid_dtd=True + ) + self.assertRaises( + DTDForbidden, self.parseString, self.get_content(self.xml_quadratic), forbid_dtd=True + ) + self.assertRaises( + DTDForbidden, self.parseString, self.get_content(self.xml_external), forbid_dtd=True + ) + self.assertRaises( + DTDForbidden, self.parseString, self.get_content(self.xml_dtd), forbid_dtd=True + ) if self.iterparse: - self.assertRaises(DTDForbidden, self.iterparse, - self.xml_bomb, forbid_dtd=True) - self.assertRaises(DTDForbidden, self.iterparse, - self.xml_quadratic, forbid_dtd=True) - self.assertRaises(DTDForbidden, self.iterparse, - self.xml_external, forbid_dtd=True) - self.assertRaises(DTDForbidden, self.iterparse, - self.xml_dtd, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.iterparse, self.xml_bomb, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.iterparse, self.xml_quadratic, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.iterparse, self.xml_external, forbid_dtd=True) + self.assertRaises(DTDForbidden, self.iterparse, self.xml_dtd, forbid_dtd=True) def test_dtd_with_external_ref(self): if self.dtd_external_ref: - self.assertRaises(self.external_ref_exception, self.parse, - self.xml_dtd) + self.assertRaises(self.external_ref_exception, self.parse, self.xml_dtd) else: self.parse(self.xml_dtd) def test_external_ref(self): - self.assertRaises(self.external_ref_exception, self.parse, - self.xml_external, forbid_entities=False) + self.assertRaises( + self.external_ref_exception, self.parse, self.xml_external, forbid_entities=False + ) def test_external_file_ref(self): content = self.get_content(self.xml_external_file) @@ -177,13 +164,13 @@ class BaseTests(DefusedTestCase): content = content.replace(b"/PATH/TO", here) else: content = content.replace("/PATH/TO", HERE) - self.assertRaises(self.external_ref_exception, self.parseString, - content, forbid_entities=False) + self.assertRaises( + self.external_ref_exception, self.parseString, content, forbid_entities=False + ) def test_allow_expansion(self): self.parse(self.xml_bomb2, forbid_entities=False) - self.parseString(self.get_content(self.xml_bomb2), - forbid_entities=False) + self.parseString(self.get_content(self.xml_bomb2), forbid_entities=False) class TestDefusedElementTree(BaseTests): @@ -289,8 +276,10 @@ class TestDefusedSax(BaseTests): with self.assertRaises(ExternalReferenceForbidden) as ctx: self.parse(self.xml_external, forbid_entities=False) - msg = ("ExternalReferenceForbidden" - "(system_id='http://www.w3schools.com/xml/note.xml', public_id=None)") + msg = ( + "ExternalReferenceForbidden" + "(system_id='http://www.w3schools.com/xml/note.xml', public_id=None)" + ) self.assertEqual(str(ctx.exception), msg) self.assertEqual(repr(ctx.exception), msg) @@ -323,6 +312,7 @@ class TestDefusedLxml(BaseTests): return self.module.tostring(tree) if not LXML3: + def test_entities_forbidden(self): self.assertRaises(NotSupportedError, self.parse, self.xml_bomb) @@ -337,8 +327,7 @@ class TestDefusedLxml(BaseTests): def test_restricted_element1(self): try: - tree = self.module.parse(self.xml_bomb, forbid_dtd=False, - forbid_entities=False) + tree = self.module.parse(self.xml_bomb, forbid_dtd=False, forbid_entities=False) except XMLSyntaxError: self.skipTest("lxml detects entityt reference loop") root = tree.getroot() @@ -355,8 +344,7 @@ class TestDefusedLxml(BaseTests): def test_restricted_element2(self): try: - tree = self.module.parse(self.xml_bomb2, forbid_dtd=False, - forbid_entities=False) + tree = self.module.parse(self.xml_bomb2, forbid_dtd=False, forbid_entities=False) except XMLSyntaxError: self.skipTest("lxml detects entityt reference loop") root = tree.getroot() @@ -404,11 +392,10 @@ class TestDefusedLxml(BaseTests): def test_lxml_warnings(self): self.assertTrue(lxml_warnings) self.assertEqual(lxml_warnings[0].category, DeprecationWarning) - self.assertIn('tests.py', lxml_warnings[0].filename) + self.assertIn("tests.py", lxml_warnings[0].filename) class XmlRpcTarget(object): - def __init__(self): self._data = [] @@ -451,8 +438,7 @@ class TestXmlRpc(DefusedTestCase): self.assertRaises(EntitiesForbidden, self.parse, self.xml_bomb) self.assertRaises(EntitiesForbidden, self.parse, self.xml_quadratic) self.parse(self.xml_dtd) - self.assertRaises(DTDForbidden, self.parse, self.xml_dtd, - forbid_dtd=True) + self.assertRaises(DTDForbidden, self.parse, self.xml_dtd, forbid_dtd=True) # def test_xmlrpc_unpatched(self): # for fname in (self.xml_external, self.xml_dtd): @@ -466,7 +452,6 @@ class TestXmlRpc(DefusedTestCase): class TestDefusedGzip(DefusedTestCase): - def get_gzipped(self, length): f = io.BytesIO() gzf = gzip.GzipFile(mode="wb", fileobj=f) |