Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ mistune<2.0.0
m2r==0.3.1
sphinx_rtd_theme
pan-python==0.17.0
defusedxml==0.7.1
5 changes: 3 additions & 2 deletions panos/userid.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from copy import deepcopy
from xml.sax.saxutils import escape, quoteattr

import defusedxml.ElementTree as defused_ET
from pan.xapi import PanXapiError

import panos.errors as err
Expand Down Expand Up @@ -62,7 +63,7 @@ def __init__(self, device, prefix="", ignore_dup_errors=True):
self.ignore_dup_errors = ignore_dup_errors

# Build the initial uid-message
self._uidmessage = ET.fromstring(
self._uidmessage = defused_ET.fromstring(
"<uid-message>"
+ "<version>1.0</version>"
+ "<type>update</type>"
Expand Down Expand Up @@ -658,7 +659,7 @@ def get_user_tags(self, user=None, prefix=None):
msg.append("<user>{0}</user>".format(escape(user)))
msg.append("</registered-user></object></show>")

cmd = ET.fromstring("".join(msg))
cmd = defused_ET.fromstring("".join(msg))
if user is None:
start_elm = cmd.find("./object/registered-user/all/start-point")

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ classifiers = [
[tool.poetry.dependencies]
python = "^2.7 || ^3.5"
pan-python = "^0.17.0"
defusedxml = "^0.7.1"

[tool.poetry.group.dev.dependencies]
pytest = {version = "^5.3.2", python = "^3.5"}
Expand Down
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pan-python==0.17.0 \
defusedxml==0.7.1 ; python_version >= "2.7" and python_version < "3.0.dev0" or python_version >= "3.5" and python_version < "4.0" \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
pan-python==0.17.0 ; python_version >= "2.7" and python_version < "3.0" or python_version >= "3.5" and python_version < "4.0" \
--hash=sha256:9c074ea2f69a63996a6fefe8935d60dca61660e14715ac19d257ea9b1c41c6e2 \
--hash=sha256:f4674e40763c46d5933244b3059a57884e4e28205ef6d0f9ce2dc2013e3db010
14 changes: 14 additions & 0 deletions tests/test_userid.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
import unittest
import xml.etree.ElementTree as ET

import defusedxml.common

import panos.firewall
import panos.panorama
import panos.userid


class TestUserId(unittest.TestCase):
Expand Down Expand Up @@ -157,6 +160,17 @@ def test_get_group_members_escapes_group(self):
self.assertEqual(names[0].text, evil)
self.assertIsNone(parsed.find(".//evil"))

def test_userid_uses_defused_xml_parser(self):
# panos.userid must parse XML through defusedxml, not the
# unprotected stdlib parser, to avoid XXE/billion-laughs attacks.
xxe_payload = (
"<?xml version='1.0'?>"
"<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>"
"<uid-message>&xxe;</uid-message>"
)
with self.assertRaises(defusedxml.common.EntitiesForbidden):
panos.userid.defused_ET.fromstring(xxe_payload)


if __name__ == "__main__":
unittest.main()