MediaWiki (wikipedia.org) – Unauthenticated Remote Code Execution

The vulnerability (CVE-2014-1610) allows an unauthenticated attacker to execute code remotely on a vulnerable MediaWiki installation.
It requires the DjVu file format in order to be exploited (built in by default).

MediaWiki is an open-source web platform used to create and maintain wikis. One of the major sites using the system is Wikipedia.org and alongside the rest of the WikiMedia foundation.

Note: This vulnerability was found back in 2014, as part of my work at Check Point’s Research group.
This is the first time the details are released publicly.

 

Vulnerable Versions

1.22.x before 1.22.2, 1.21.x before 1.21.5 and 1.19.x before 1.19.11

 

Technical Description

The MediaWiki software is capable of editing uploaded images. One of the file formats supported is “DjVu” – an alternative to PDF.
Because PHP doesn’t support this image format natively, MediaWiki uses external binaries in order to rotate, re-size, or crop DjVu images.

The script “thumb.php” is used to create thumbnails from given images, with the size, page and other relevant parameters controlled by the user.  “thumb.php” first initializes an image object based on the image mime type, and then supply it with the user parameters. In our case, a DjVu image, an instance of the “DjVuHandler” class is created.
Later on, after verifying all the required parameters has been inserted, “thumb.php” calls the method “doTransform()” on our “DjVuHandler” instance.

“doTransform()” tries to validate the supplied user parameters by calling the method “normaliseParams()”, which is responsible for validating the user controlled parameters for any malicious input – code injections (“; whoami;”), logical errors (invalid width/height), or data types differentials (an array instead of a string).
One of the parameters used is the “page” parameter, responsible for displaying a specific page from a given DjVu or PFD file. “normaliseParams()” checks that the page parameter is valid by checking whether it is smaller than the maximum number of pages in the given file and that it’s larger than 1. The code being used for the validation can be seen here:

if ( !isset( $params['page'] ) ) {
	$params['page'] = 1;
} else {
	// If the request page is larger than the number of pages
	if ( $params['page'] > $image->pageCount() ) {
		$params['page'] = $image->pageCount();
	}

	// If the requested page is 0 or negative
	if ( $params['page'] < 1 ) {
		$params['page'] = 1;
	}
}

That way, the function validates the inserted page number both logically and security wise, by making sure it’s an actual number and that it’s in the valid pages range. If the page number doesn’t match the given specifications, its value is being changed to the number one (1).
Even though this looks secure in first glance, let’s have a look at how PHP handles integer type conversions.

PHP converts a string into an integer by using the “strtod()” C function, which returns an integer representation of a given string.
“strtod()” does that by returning every character in the string until the first non-numeric character. So, if we will use the string “1abc” as our page number, PHP will treat it as a regular integer – the number “1”, completely ignoring all the other characters in the string.

This allows us to completely bypass the page parameter validation, as MediaWiki doesn’t check that our “page” parameter is only an integer, it checks that it’s also an integer.
Later on, the DjVu binary command line is parsed and executed, as can be seen in the following code:

// Parse the CMD string
$cmd = '(' . wfEscapeShellArg( $wgDjvuRenderer ) . 
	" -format=ppm -page={$page}" . 
	" -size={$params['physicalWidth']}x{$params['physicalHeight']} " . 
	wfEscapeShellArg( $srcPath );
...
// Execute the CMD string
$err = wfShellExec( $cmd, $retval );

As seen, the “page” parameter (highlighted in the code) is inserted without calling any other input validation functions, and is therefore being executed as is. This means that if an attacker will set the page parameter to something like the string “1||whoami||”, the binary whoami” will be executed at the server, effectively allowing us to exploit a Remote Code Execution attack.

Leave a Reply

Your email address will not be published. Required fields are marked *