PortSwigger's "Exploiting XXE using external entities to retrieve files" Walkthrough

This is the first of the XXE Labs from PortSwigger. For this walkthrough, you’ll need to have Burp Suite set up, as well as a Portswigger Academy account.

Log in to your Academy account and then view the lab at https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-retrieve-files. This is accessible from the “all labs” view or from the XXE page.

Challenge Information

Click the “Access the Lab” button and you will be taken to a temporary website that is created for your account. This will be in format https://<random string here>.web-security-academy.net/.

XXE stands for XML external entities. XXE is a custom type of XML entity that allows for values to be loaded outside of the document type definition (DTD). In the case of this lab, that means we can define a special entity that allows us to read in arbitrary files from the file system.

The website itself looks like this, the usual shopping site from the Academy labs:

If you click in to one of the product pages, and scroll down past the weird descriptions, you can see a stock checker:

Examining the stock checker

With Burp Suite open and your proxy running (see our guide for setup), make a stock check request in your browser. Then, look at the request in Burp:

The bottom lines (line 17) show the XML input being sent by our browser to the server. This is what we’ll want to modify to retrieve /etc/passwd.

The XXE page from PortSwigger covers a variety of different (malicious) applications. The one that’s relevant here is the file read one:

The page also includes sample code:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>

If we compare this with the existing XML object, we already have the first <?xml> tag:

We need to add the DOCTYPE. The “foo” variable appears to be a dummy variable. The part inside the [] is the important part. We’re declaring an ENTITY that we will assign to a variable to reference later. The example used xxe, I changed mine to var. Then the SYSTEM "file:///etc/passwd" part is the command that will be executed.

<!DOCTYPE foo [ <!ENTITY var SYSTEM "file:///etc/passwd"> ]>

Let’s add this to our modified request (viewed in Burp Suite’s Repeater tab; right-click a request in the History view and select Send to Repeater).

That covers our first modification, the DOCTYPE element that defines the external entity. Next, we need to edit a data value to return the variable.

To do so, you can remove one of the numbers (such as the productId value) and replace it with a reference to the external entity, which I called var and the original example called xxe. Whatever you name it, add & to the front and ; to the end to make it act as a variable.

Here’s our fully modified request:

Send this request, and you should get /etc/passwd back:

Since this worked, visit the site in your browser to see that you’ve gotten credit: