A simple XXE test suite generated specifically for SAML interfaces.
SAML is an XML based markup language and XML parsers employed by SAML endpoints may be susceptible to XXE attacks. SAML messages are usually transmitted using Base64Url()
encoding and may additionally be deflated (depending on the used SAML binding). This makes testing for XXE vulnerabilties more difficult, as the encoding needs to be applied to each test-vector when evaluating a SAML endpoint for XXE vulnerabilities.
saml_xxe_test.py
automatically performs the required encoding and additionally comes with a predefined set of default test-vectors, most of which attempt to provoke out-of-band feedback. Using saml_xxe_test.py
, a security auditor can semi-automatically check a SAML endpoint for XXE vulnerabilities. In its simplest form, running saml_xxe_test.py
only requires two arguments:
./saml_xxe_test.py -f url_file.txt -t TARGET
Here, url_file.txt
contains URLs of a listener service set up by the auditor and TARGET
is replaced by the URL of the SAML endpoint to be tested.
As indicated above, saml_xxe_test.py
reads templates of test-vectors from a YAML file and generates a pool of test-vectors by combining the entity definitions of the templates with various protocol schemes, DTD keywords, and provided URLs of a listener service controlled by the auditor. The generated test-vectors are subsequently sent to the targeted SAML endpoint. Requests as well as responses are logged, and the auditor can assess whether or not the tested service is vulnerable by watching out for incoming requests on the prepared listener service. This test scenario is depicted below.
- Set up a listener which waits for incoming requests from the service being tested. This could simply be a web server if you only test the
http
scheme. - Generate a file
url_file.txt
that contains -preferably unique- listener URLs, one per line1. The URLs must not contain a protocol scheme, i.e., uselocalhost:5000/RANDOM-UUID
(note the missinghttp://
) if the tested service and your listener are both running onlocalhost
. Ensure that your listener is bound to the ports used inurl_file.txt
and that the listener logs incoming requests. - Using
Python 3
, run./saml_xxe_test.py -f url_file.txt -t TARGET
This will start sending the default test vectors (http
scheme only) as theSAMLRequest
parameter via aHTTP-POST Binding
to the SAML endpointTARGET
. If the service atTARGET
is vulnerable (and has network access), your listener should receive a corresponding request. Incoming requests can easily be mapped to the test-vectors being sent if you use unique identifiers in the URLs listed inurl_file.txt
.
saml_xxe_test.py
allows configuration of the following settings from the commandline.
./saml_xxe_test.py -h
usage: saml_xxe_test.py [-h] -f URL_FILE [-o OUTPUT_FILE] [-t TARGET]
[--vector_file VECTOR_FILE] [-m {POST,GET}] [-a]
[-p PROXY] [-d] [-i INTERVAL] [-v] [--timeout TIMEOUT]
[--dump_vectors] [-s {SAMLRequest,SAMLResponse}]
[--store_test STORE_TEST]
required arguments:
-f URL_FILE, --url_file URL_FILE
Full path of Burp Collaborator URL File
-t TARGET, --target TARGET
Target URL as SCHEME://IP:PORT, e.g.,
http://localhost:5000
optional arguments:
-h, --help Show this help message and exit.
-o OUTPUT_FILE, --output_file OUTPUT_FILE
If no output file is defined, output to terminal is
enabled.
--vector_file VECTOR_FILE
A yaml file containing a list of XXE Vectors, defaults
to ./default_phase1_vectors.yml The vectors may
contain the following placeholders:
"${PROTOCOLHANDLE}", "${SYSPUB}",
"${PUBLIC_URL_PLACEHOLDER}".
-m {POST,GET}, --method {POST,GET}
Select which HTTP method to use, default is POST. If
set to GET, deflate compression is applied to the SAML
message (HTTP-Redirect Binding).
-a, --aggressive Build vectors using more protocols.
-p PROXY, --proxy PROXY
Add http(s) proxy address as IP:PORT like
127.0.0.1:8080.
-d, --debug Enable debug mode.
-i INTERVAL, --interval INTERVAL
Set request interval delay in seconds. Default is a
random interval in (5, 15) seconds.
-v, --verbose Enabled verbose mode. Sends response to stdout. Auto
enabled if no output file is specified.
--timeout TIMEOUT Seconds to wait until a request is aborted as timed
out. Default is 30 seconds.
--dump_vectors Print generated DTD vectors and exit.
-s {SAMLRequest,SAMLResponse}, --samlparam {SAMLRequest,SAMLResponse}
The HTTP parametername to used. Uses SAMLRequest if
not defined.
--store_test STORE_TEST
Store serialized response objects in a given filename
(as python shelve). May be useful for later analysis.
- Implement some kind of session macro to allow for testing SAML endpoints which require a valid session before parsing XML (e.g., AssertionConsumerService that checks if the
RelayState
parameter is bound to a session cookie first). - Integrate more closely with a listener service. As an example when using Burp Collaborator, poll for incoming requests and automate evaluation. Alternatively, an active scanner could be integrated into the EsPReSSO extension
- OWASP has a site with general information about XXE
- Countermeasures against XXE as recommended by OWASP
- To learn more about XXE in SAML, check out https://web-in-security.blogspot.de/2014/11/detecting-and-exploiting-xxe-in-saml.html
- A comprehensive list of XXE vectors https://web-in-security.blogspot.de/2016/03/xxe-cheat-sheet.html
Footnote 1: If you are using Burp Collaborator as your listener, simply copy the required number of Collaborator URLs into your url_file.txt
. At the time of writing, Burp Collaborator supports a number of protocols including http
and https
. ↩