Add XML vulnerability checking
This adds an XML plug-in based on the documentation an defusedxml. Change-Id: Id775cd0f3d45fd2e9dac1c5bca5c36e0b5618066
This commit is contained in:
parent
6e2e387e4f
commit
18285c1bb9
|
@ -0,0 +1,279 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# Most of this file is based off of Christian Heimes' work on defusedxml:
|
||||
# https://pypi.python.org/pypi/defusedxml/#defusedxml-sax
|
||||
|
||||
import bandit
|
||||
from bandit.core.test_properties import *
|
||||
|
||||
|
||||
###############################################################################
|
||||
# check function calls
|
||||
###############################################################################
|
||||
@checks('Call')
|
||||
def etree_celement_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'iterparse', 'fromstring', 'XMLParser']
|
||||
if 'xml.etree.cElementTree' == qual and func in blacklist:
|
||||
s = ("Using xml.etree.cElementTree.%s to parse untrusted XML data"
|
||||
" is known to be vulnerable to XML attacks. Replace "
|
||||
" xml.etree.cElementTree.%s with defusedxml.cElementTree.%s"
|
||||
" function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def etree_element_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'iterparse', 'fromstring', 'XMLParser']
|
||||
if 'xml.etree.ElementTree' == qual and func in blacklist:
|
||||
s = ("Using xml.etree.ElementTree.%s to parse untrusted XML data"
|
||||
" is known to be vulnerable to XML attacks. Replace"
|
||||
" xml.etree.ElementTree.%s with defusedxml.ElementTree.%s"
|
||||
" function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def expatreader_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['create_parser']
|
||||
if 'xml.sax.expatreader' == qual and func in blacklist:
|
||||
s = ("Using xml.sax.expatreader.%s to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" xml.sax.expatreader.%s with defusedxml.expatreader.%s"
|
||||
" function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def expatbuilder_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'parseString']
|
||||
if 'xml.dom.expatbuilder' == qual and func in blacklist:
|
||||
s = ("Using xml.dom.expatbuilder.%s to parse untrusted XML data"
|
||||
" is known to be vulnerable to XML attacks. Replace"
|
||||
" xml.dom.expatbuilder.%s with defusedxml.expatbuilder.%s"
|
||||
" function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def sax_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'parseString', 'make_parser']
|
||||
if 'xml.sax' == qual and func in blacklist:
|
||||
s = ("Using xml.sax.%s to parse untrusted XML data is known to"
|
||||
" be vulnerable to XML attacks. Replace xml.sax.%s with"
|
||||
" defusedxml.sax.%s function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def minidom_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'parseString']
|
||||
if 'xml.dom.minidom' == qual and func in blacklist:
|
||||
s = ("Using xml.dom.minidom.%s to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" xml.dom.minidom.%s with defusedxml.minidom.%s"
|
||||
" function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def pulldom_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'parseString']
|
||||
if 'xml.dom.pulldom' == qual and func in blacklist:
|
||||
s = ("Using xml.dom.pulldom.%s to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" xml.dom.pulldom.%s with defusedxml.pulldom.%s function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
@checks('Call')
|
||||
def lxml_function_calls(context):
|
||||
if type(context.call_function_name_qual) == str:
|
||||
qlist = context.call_function_name_qual.split('.')
|
||||
qual = '.'.join(qlist[:-1])
|
||||
func = qlist[-1]
|
||||
blacklist = ['parse', 'fromstring', 'RestrictedElement',
|
||||
'GlobalParserTLS', 'getDefaultParser', 'check_docinfo']
|
||||
if 'lxml.etree' == qual and func in blacklist:
|
||||
s = ("Using lxml.etree.%s to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" lxml.etree.%s with defused.lxml.%s function.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.MEDIUM,
|
||||
text=s % (func, func, func))
|
||||
|
||||
|
||||
###############################################################################
|
||||
# check imports
|
||||
###############################################################################
|
||||
@checks('Import', 'ImportFrom')
|
||||
def etree_celement_import(context):
|
||||
if context.is_module_being_imported('xml.etree.cElementTree'):
|
||||
s = ("Using xml.etree.cElementTree to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" xml.etree.cElementTree with defusedxml.cElementTree package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def etree_element_import(context):
|
||||
if context.is_module_being_imported('xml.etree.ElementTree'):
|
||||
s = ("Using xml.etree.ElementTree to parse untrusted XML data is"
|
||||
" known to be vulnerable to XML attacks. Replace"
|
||||
" xml.etree.ElementTree with defusedxml.ElementTree package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def expatreader_import(context):
|
||||
if context.is_module_being_imported('xml.sax.expatreader'):
|
||||
s = ("Using xml.sax.expatreader to parse untrusted XML data is known"
|
||||
" to be vulnerable to XML attacks. Replace xml.sax.expatreader"
|
||||
" with defusedxml.expatreader package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def sax_import(context):
|
||||
if context.is_module_being_imported('xml.sax'):
|
||||
s = ("Using xml.sax to parse untrusted XML data is known to be"
|
||||
" vulnerable to XML attacks. Replace xml.sax with defusedxml.sax"
|
||||
" package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def expatbuilder_import(context):
|
||||
if context.is_module_being_imported('xml.dom.expatbuilder'):
|
||||
s = ("Using xml.dom.expatbuilder to parse untrusted XML data is known"
|
||||
" to be vulnerable to XML attacks. Replace xml.dom.expatbuilder"
|
||||
" with defusedxml.expatbuilder package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def minidom_import(context):
|
||||
if context.is_module_being_imported('xml.dom.minidom'):
|
||||
s = ("Using xml.dom.minidom to parse untrusted XML data is known to be"
|
||||
" vulnerable to XML attacks. Replace xml.dom.minidom with"
|
||||
" defusedxml.minidom package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def pulldom_import(context):
|
||||
if context.is_module_being_imported('xml.dom.pulldom'):
|
||||
s = ("Using xml.dom.pulldom to parse untrusted XML data is known to be"
|
||||
" vulnerable to XML attacks. Replace xml.dom.pulldom with"
|
||||
" defusedxml.pulldom package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
# this one is 'HIGH' instead of 'LOW' because we know the entire package has
|
||||
# to be monkeypatched via defusedxml.xmlrpc.monkey_patch()
|
||||
@checks('Import', 'ImportFrom')
|
||||
def xmlrpclib_import(context):
|
||||
if context.is_module_being_imported('xmlrpclib'):
|
||||
s = ("Using xmlrpclib to parse untrusted XML data is known to be"
|
||||
" vulnerable to XML attacks. Use defused.xmlrpc.monkey_patch()"
|
||||
" function to monkey-patch xmlrpclib and mitigate XML"
|
||||
" vulnerabilities.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
||||
|
||||
|
||||
@checks('Import', 'ImportFrom')
|
||||
def lxml_import(context):
|
||||
if(context.is_module_being_imported('lxml.etree') or
|
||||
context.is_module_being_imported('lxml')):
|
||||
s = ("Using lxml.etree to parse untrusted XML data is known to be"
|
||||
" vulnerable to XML attacks. Replace lxml.etree with"
|
||||
" defused.lxml package.")
|
||||
return bandit.Issue(
|
||||
severity=bandit.LOW,
|
||||
confidence=bandit.HIGH,
|
||||
text=s)
|
|
@ -0,0 +1,219 @@
|
|||
Use safe XML libraries to avoid XML vulnerabilities
|
||||
=====================
|
||||
XML vulnerabilities are known and well studied. The [defusedxml](https://pypi.python.org/pypi/defusedxml/) library provides a great synposis of XML vulnerabilities, how they're exploited, and which Python libraries are vulnerable to which attacks.
|
||||
|
||||
Most XML vulnerabilities essentially amount to Denial of Service attacks but as [previous blackhat presentations](https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf) have shown, XML vulnerabilities can lead to local file reading, intranet access, and some times remote code execution.
|
||||
|
||||
We don't attempt to rehash the details of each vulnerability class and instead recommend those interested read [defuxedxml](https://pypi.python.org/pypi/defusedxml/)'s page, including references.
|
||||
|
||||
### Incorrect
|
||||
Currently, the following Python XML libraries are vulnerable to some form of XML attack:
|
||||
* [xml.sax](https://docs.python.org/2/library/xml.sax.html)
|
||||
- vulnerable to: billion laughs, quadratic blowup, external entity expansion, DTD retrieval
|
||||
* [xml.etree.ElementTree](https://docs.python.org/2/library/xml.etree.elementtree.html)
|
||||
- vulnerable to: billion laughs, quadratic blowup
|
||||
* [xml.dom.minidom](https://docs.python.org/2/library/xml.dom.minidom.html)
|
||||
- vulnerable to: billion laughs, quadratic blowup
|
||||
* [xml.dom.pulldom](https://docs.python.org/2/library/xml.dom.pulldom.html)
|
||||
- vulnerable to: billion laughs, quadratic blowup, external entity expansion, DTD retrieval
|
||||
* [xmlrpclib](https://docs.python.org/2/library/xmlrpclib.html)
|
||||
- vulnerable to: billion laughs, quadratic blowup, decompression bomb
|
||||
|
||||
[Python's XML library page](https://docs.python.org/2/library/xml.html#xml-vulnerabilities) indicates that [defusedxml](https://pypi.python.org/pypi/defusedxml/) is the correct choice for XML libraries.
|
||||
|
||||
### Correct
|
||||
#### xml.sax
|
||||
Replace all xml.sax parsers with defusedxml parsers:
|
||||
* ```xml.sax.parser()``` -> ```defusedxml.sax.parser()```
|
||||
* ```xml.sax.parseString()``` -> ```defusedxml.sax.parseString()```
|
||||
* ```xml.sax.create_parser()``` -> ```defusedxml.sax.parseString()```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
import xml.sax
|
||||
|
||||
class ExampleContentHandler(xml.sax.ContentHandler):
|
||||
def __init__(self):
|
||||
xml.sax.ContentHandler.__init__(self)
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
print 'start:', name
|
||||
|
||||
def endElement(self, name):
|
||||
print 'end:', name
|
||||
|
||||
def characters(self, content):
|
||||
print 'chars:', content
|
||||
|
||||
def main():
|
||||
xml.sax.parse(open('input.xml'), ExampleContentHandler())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
import xml.sax
|
||||
import defusedxml.sax
|
||||
|
||||
class ExampleContentHandler(xml.sax.ContentHandler):
|
||||
def __init__(self):
|
||||
xml.sax.ContentHandler.__init__(self)
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
print 'start:', name
|
||||
|
||||
def endElement(self, name):
|
||||
print 'end:', name
|
||||
|
||||
def characters(self, content):
|
||||
print 'chars:', content
|
||||
|
||||
def main():
|
||||
defusedxml.sax.parse(open('input.xml'), ExampleContentHandler())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
#### xml.etree.ElementTree
|
||||
Replace the following instances of xml.etree.ElementTree functions with the corresponding defusedxml functions:
|
||||
* ```xml.etree.ElementTree.parse()``` -> ```defusedxml.ElementTree.parse()```
|
||||
* ```xml.etree.ElementTree.iterparse()``` -> ```defusedxml.ElementTree.iterparse()```
|
||||
* ```xml.etree.ElementTree.fromstring()``` -> ```defusedxml.ElementTree.fromstring()```
|
||||
* ```xml.etree.ElementTree.XMLParser``` -> ```defusedxml.ElementTree.XMLParser```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
import xml.etree.ElementTree as ET
|
||||
tree = ET.parse("input.xml")
|
||||
root = tree.getroot()
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
import defusedxml.ElementTree as ET
|
||||
tree = ET.parse("input.xml")
|
||||
root = tree.getroot()
|
||||
```
|
||||
|
||||
#### xml.etree.cElementTree
|
||||
Replace the following instances of xml.etree.cElementTree functions with the corresponding defusedxml functions:
|
||||
* ```xml.etree.cElementTree.parse()``` -> ```defusedxml.cElementTree.parse()```
|
||||
* ```xml.etree.cElementTree.iterparse()``` -> ```defusedxml.cElementTree.iterparse()```
|
||||
* ```xml.etree.cElementTree.fromstring()``` -> ```defusedxml.cElementTree.fromstring()```
|
||||
* ```xml.etree.cElementTree.XMLParser``` -> ```defusedxml.cElementTree.XMLParser```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
import xml.etree.cElementTree as ET
|
||||
tree = ET.parse("input.xml")
|
||||
root = tree.getroot()
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
import defusedxml.cElementTree as ET
|
||||
tree = ET.parse("input.xml")
|
||||
root = tree.getroot()
|
||||
```
|
||||
|
||||
#### xml.dom.minidom
|
||||
Replace the following instances of xml.dom.minidom functions with the corresponding defusedxml functions:
|
||||
* ```xml.dom.minidom.parse()``` -> ```defusedxml.minidom.parse()```
|
||||
* ```xml.dom.minidom.parseString()``` -> ```defusedxml.minidom.parseString()```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
from xml.dom.minidom import parseString
|
||||
parseString('<myxml>Some data<empty/> some more data</myxml>')
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
from defusedxml.minidom import parseString
|
||||
parseString('<myxml>Some data<empty/> some more data</myxml>')
|
||||
```
|
||||
|
||||
#### xml.dom.pulldom
|
||||
Replace the following instances of xml.dom.pulldom functions with the corresponding defusedxml functions:
|
||||
* ```xml.dom.pulldom.parse()``` -> ```defusedxml.pulldom.parse()```
|
||||
* ```xml.dom.pulldom.parseString()``` -> ```defusedxml.pulldom.parseString()```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
from xml.dom.pulldom import parseString
|
||||
parseString('<myxml>Some data<empty/> some more data</myxml>')
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
from defusedxml.pulldom import parseString
|
||||
parseString('<myxml>Some data<empty/> some more data</myxml>')
|
||||
```
|
||||
|
||||
#### xmlrpclib
|
||||
Taken directly from the defusedxml page:
|
||||
"The function monkey_patch() enables the fixes, unmonkey_patch() removes the patch and puts the code in its former state."
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
from xmlrpclib import ServerProxy, Error
|
||||
|
||||
server = ServerProxy("http://betty.userland.com")
|
||||
|
||||
print server
|
||||
|
||||
try:
|
||||
print server.examples.getStateName(41)
|
||||
except Error as v:
|
||||
print "ERROR", v
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
from xmlrpclib import ServerProxy, Error
|
||||
import defusedxml.xmlrpc
|
||||
|
||||
defusedxml.xmlrpc.monkey_patch()
|
||||
|
||||
server = ServerProxy("http://betty.userland.com")
|
||||
|
||||
print server
|
||||
|
||||
try:
|
||||
print server.examples.getStateName(41)
|
||||
except Error as v:
|
||||
print "ERROR", v
|
||||
```
|
||||
|
||||
#### lxml.etree
|
||||
Replace the following instances of lxml functions with the corresponding defusedxml functions:
|
||||
* ```lxml.etree.parse()``` -> ```defusedxml.lxml.parse```
|
||||
* ```lxml.etree.fromstring()``` -> ```defusedxml.lxml.fromstring()```
|
||||
* ```lxml.etree.RestrictedElement()``` -> ```defusedxml.lxml.RestrictedElement()```
|
||||
* ```lxml.etree.getDefaultParser()``` -> ```defusedxml.lxml.getDefaultParser()```
|
||||
* ```lxml.etree.check_docinfo()``` -> ```defusedxml.lxml.check_docinfo()```
|
||||
|
||||
Intead of this:
|
||||
```python
|
||||
from lxml import etree
|
||||
root = etree.parse('input.xml')
|
||||
```
|
||||
|
||||
Do this:
|
||||
```python
|
||||
from defusedxml.lxml import parse
|
||||
root = parse('input.xml')
|
||||
|
||||
```
|
||||
## References
|
||||
* https://pypi.python.org/pypi/defusedxml/
|
||||
* https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf
|
||||
* https://docs.python.org/2/library/xml.sax.html
|
||||
* https://docs.python.org/2/library/xml.etree.elementtree.html
|
||||
* https://docs.python.org/2/library/xml.dom.minidom.html
|
||||
* https://docs.python.org/2/library/xml.dom.pulldom.html
|
||||
* https://docs.python.org/2/library/xmlrpclib.html
|
||||
* https://docs.python.org/2/library/xml.html#xml-vulnerabilities
|
|
@ -0,0 +1,18 @@
|
|||
import xml.etree.cElementTree as badET
|
||||
import defusedxml.cElementTree as goodET
|
||||
|
||||
xmlString = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!</body>\n</note>"
|
||||
|
||||
# unsafe
|
||||
tree = badET.fromstring(xmlString)
|
||||
print tree
|
||||
badET.parse('filethatdoesntexist.xml')
|
||||
badET.iterparse('filethatdoesntexist.xml')
|
||||
a = badET.XMLParser()
|
||||
|
||||
# safe
|
||||
tree = goodET.fromstring(xmlString)
|
||||
print tree
|
||||
goodET.parse('filethatdoesntexist.xml')
|
||||
goodET.iterparse('filethatdoesntexist.xml')
|
||||
a = goodET.XMLParser()
|
|
@ -0,0 +1,18 @@
|
|||
import xml.etree.ElementTree as badET
|
||||
import defusedxml.ElementTree as goodET
|
||||
|
||||
xmlString = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!</body>\n</note>"
|
||||
|
||||
# unsafe
|
||||
tree = badET.fromstring(xmlString)
|
||||
print tree
|
||||
badET.parse('filethatdoesntexist.xml')
|
||||
badET.iterparse('filethatdoesntexist.xml')
|
||||
a = badET.XMLParser()
|
||||
|
||||
# safe
|
||||
tree = goodET.fromstring(xmlString)
|
||||
print tree
|
||||
goodET.parse('filethatdoesntexist.xml')
|
||||
goodET.iterparse('filethatdoesntexist.xml')
|
||||
a = goodET.XMLParser()
|
|
@ -0,0 +1,10 @@
|
|||
import xml.dom.expatbuilder as bad
|
||||
import defusedxml.expatbuilder as good
|
||||
|
||||
bad.parse('filethatdoesntexist.xml')
|
||||
good.parse('filethatdoesntexist.xml')
|
||||
|
||||
xmlString = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!</body>\n</note>"
|
||||
|
||||
bad.parseString(xmlString)
|
||||
good.parseString(xmlString)
|
|
@ -0,0 +1,5 @@
|
|||
import xml.sax.expatreader as bad
|
||||
import defusedxml.expatreader as good
|
||||
|
||||
p = bad.create_parser()
|
||||
b = good.create_parser()
|
|
@ -0,0 +1,9 @@
|
|||
import lxml.etree
|
||||
import lxml
|
||||
from lxml import etree
|
||||
from defusedxml.lxml import fromstring
|
||||
from defuxedxml import lxml as potatoe
|
||||
|
||||
xmlString = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!</body>\n</note>"
|
||||
root = lxml.etree.fromstring(xmlString)
|
||||
root = fromstring(xmlString)
|
|
@ -0,0 +1,14 @@
|
|||
from xml.dom.minidom import parseString as badParseString
|
||||
from defusedxml.minidom import parseString as goodParseString
|
||||
a = badParseString("<myxml>Some data some more data</myxml>")
|
||||
print a
|
||||
b = goodParseString("<myxml>Some data some more data</myxml>")
|
||||
print b
|
||||
|
||||
|
||||
from xml.dom.minidom import parse as badParse
|
||||
from defusedxml.minidom import parse as goodParse
|
||||
a = badParse("somfilethatdoesntexist.xml")
|
||||
print a
|
||||
b = goodParse("somefilethatdoesntexist.xml")
|
||||
print b
|
|
@ -0,0 +1,14 @@
|
|||
from xml.dom.pulldom import parseString as badParseString
|
||||
from defusedxml.pulldom import parseString as goodParseString
|
||||
a = badParseString("<myxml>Some data some more data</myxml>")
|
||||
print a
|
||||
b = goodParseString("<myxml>Some data some more data</myxml>")
|
||||
print b
|
||||
|
||||
|
||||
from xml.dom.pulldom import parse as badParse
|
||||
from defusedxml.pulldom import parse as goodParse
|
||||
a = badParse("somfilethatdoesntexist.xml")
|
||||
print a
|
||||
b = goodParse("somefilethatdoesntexist.xml")
|
||||
print b
|
|
@ -0,0 +1,37 @@
|
|||
import xml.sax
|
||||
from xml import sax
|
||||
import defusedxml.sax
|
||||
|
||||
class ExampleContentHandler(xml.sax.ContentHandler):
|
||||
def __init__(self):
|
||||
xml.sax.ContentHandler.__init__(self)
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
print 'start:', name
|
||||
|
||||
def endElement(self, name):
|
||||
print 'end:', name
|
||||
|
||||
def characters(self, content):
|
||||
print 'chars:', content
|
||||
|
||||
def main():
|
||||
xmlString = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!</body>\n</note>"
|
||||
# bad
|
||||
xml.sax.parseString(xmlString, ExampleContentHandler())
|
||||
xml.sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler())
|
||||
sax.parseString(xmlString, ExampleContentHandler())
|
||||
sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler)
|
||||
|
||||
# good
|
||||
defusedxml.sax.parseString(xmlString, ExampleContentHandler())
|
||||
|
||||
# bad
|
||||
xml.sax.make_parser()
|
||||
sax.make_parser()
|
||||
print 'nothing'
|
||||
# good
|
||||
defusedxml.sax.make_parser()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,10 @@
|
|||
import xmlrpclib
|
||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
||||
|
||||
def is_even(n):
|
||||
return n%2 == 0
|
||||
|
||||
server = SimpleXMLRPCServer(("localhost", 8000))
|
||||
print "Listening on port 8000..."
|
||||
server.register_function(is_even, "is_even")
|
||||
server.serve_forever()
|
|
@ -68,6 +68,8 @@ class FunctionalTests(unittest.TestCase):
|
|||
:param example_script: Filename of an example script to test
|
||||
:param expect: dict with expected counts of issue types
|
||||
'''
|
||||
# reset scores for subsequent calls to check_example
|
||||
self.b_mgr.scores = []
|
||||
self.run_example(example_script)
|
||||
expected = 0
|
||||
result = 0
|
||||
|
@ -302,3 +304,41 @@ class FunctionalTests(unittest.TestCase):
|
|||
'''Test Mako templates for XSS.'''
|
||||
expect = {'SEVERITY': {'MEDIUM': 3}, 'CONFIDENCE': {'HIGH': 3}}
|
||||
self.check_example('mako_templating.py', expect)
|
||||
|
||||
def test_xml(self):
|
||||
'''Test xml vulnerabilities.'''
|
||||
expect = {'SEVERITY': {'LOW': 1, 'HIGH': 4},
|
||||
'CONFIDENCE': {'HIGH': 1, 'MEDIUM': 4}}
|
||||
self.check_example('xml_etree_celementtree.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 1, 'HIGH': 2},
|
||||
'CONFIDENCE': {'HIGH': 1, 'MEDIUM': 2}}
|
||||
self.check_example('xml_expatbuilder.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 3, 'HIGH': 1},
|
||||
'CONFIDENCE': {'HIGH': 3, 'MEDIUM': 1}}
|
||||
self.check_example('xml_lxml.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 2, 'HIGH': 2},
|
||||
'CONFIDENCE': {'HIGH': 2, 'MEDIUM': 2}}
|
||||
self.check_example('xml_pulldom.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'HIGH': 1},
|
||||
'CONFIDENCE': {'HIGH': 1}}
|
||||
self.check_example('xml_xmlrpc.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 1, 'HIGH': 4},
|
||||
'CONFIDENCE': {'HIGH': 1, 'MEDIUM': 4}}
|
||||
self.check_example('xml_etree_elementtree.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 1, 'HIGH': 1},
|
||||
'CONFIDENCE': {'HIGH': 1, 'MEDIUM': 1}}
|
||||
self.check_example('xml_expatreader.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 2, 'HIGH': 2},
|
||||
'CONFIDENCE': {'HIGH': 2, 'MEDIUM': 2}}
|
||||
self.check_example('xml_minidom.py', expect)
|
||||
|
||||
expect = {'SEVERITY': {'LOW': 1, 'HIGH': 6},
|
||||
'CONFIDENCE': {'HIGH': 1, 'MEDIUM': 6}}
|
||||
self.check_example('xml_sax.py', expect)
|
||||
|
|
Loading…
Reference in New Issue