Exploiting blind XXE to exfiltrate data using a malicious external DTD
Description
This lab has a "Check stock" feature that parses XML input but does not display the result.
To solve the lab, exfiltrate the contents of the /etc/hostname file.
Approach
Upon accessing the lab, I encountered a POST request sending XML data to the backend:
POST /product/stock HTTP/2
Host: 0a77002d0346d8688570134c009a00e5.web-security-academy.net
Cookie: session=9Q0ah1aNgGsj0KiWgbsD69sPyprr3tei
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 ...
<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
<productId>1</productId>
<storeId>1</storeId>
</stockCheck>My initial attempt to exploit XXE by fetching local files failed, likely due to input validation or XML parser hardening. Since this lab requires the exfiltration of local data, I needed to devise a new approach. Instead of relying solely on blind XXE to trigger a callback, I decided to fetch some data as well. Fortunately, the lab provided an exploit server that I could utilize.
![[XXE_server.png]]
I hosted a malicious DTD file on this server, which would be invoked in my XXE payload. This DTD file contained two crucial entities:
The first entity would read and save the file "/etc/hostname".
The second entity, a stacked one, would declare an entity responsible for sending the result of the first entity, i.e., the contents of the /etc/hostname file, to my exploit server.
Here's my malicious DTD file:
I utilized XML parameter entities due to input validation and XML parser hardening.
Next, I injected the XXE payload into the POST /product/stock request, loading my malicious DTD file to read the content of the /etc/hostname file and send it back to my exploit server.
As seen, the payload is straightforward: it calls my malicious DTD file from my exploit server. By invoking the entities stacked and exfil at the end of the payload (already declared in my malicious DTD file), I could monitor my exploit server's log. There, I observed two requests: one to retrieve my malicious DTD file and another with the content of the /etc/hostname file attached. Upon submitting this name, the lab was successfully solved.

Note: Attempting to exfiltrate multiple lines via HTTP would not work, as APIs in such scenarios often employ input sanitizers that detect characters. To read files like /etc/passwd with multiple lines, an alternative protocol such as FTP would be necessary._
Last updated