Skip to content
Field Value
Platform PortSwigger Web Security Academy
Type XXE — XInclude File Retrieval
Difficulty Practitioner
Objective Read /etc/passwd via an XInclude injection in the stock check feature

Exploiting XInclude to Retrieve Files — Writeup


Initial Observation

Going to a product and clicking "Check stock" — intercepting the request:

Screenshot
productId=1&storeId=2

No XML structure in the request body — this is a form-encoded POST. The lab description tells us the server embeds this value into a server-side XML document before parsing. We're not sending XML directly, so we can't define a DOCTYPE or inject external entities the classic way.

Injecting teto into productId to confirm it gets reflected:

productId=teto&storeId=2

Response: Invalid product ID: teto — the value lands somewhere in the XML that gets processed.


Attack Path

XInclude Injection

Since we can't control the full document structure, we use XInclude. XInclude is a W3C standard for composing XML documents from sub-documents — it lets you pull in external content using <xi:include> directives. Unlike external entities, XInclude works at the element level, so it can be placed in any data value that ends up inside an XML document. The namespace declaration (xmlns:xi) is all that's needed to activate it:

productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=2

parse="text" tells the parser to include the file as raw text rather than as an XML document. Without it, the parser would try to interpret /etc/passwd as XML and fail because it's not valid XML.

Screenshot

/etc/passwd contents come back in the response as usal, this means lab solved :P

Resources