Wordfence’s Threat Intelligence team discovered a vulnerability present in Comments – wpDiscuz, a WordPress plugin installed on over 80,000 sites.

This flaw gave unauthenticated attackers the ability to upload arbitrary files, including PHP files, and achieve remote code execution on a vulnerable site’s server.

This vulnerability was introduced in the plugin’s latest major version update.This is considered a critical security issue that could lead to remote code execution on a vulnerable site’s server. If you are running any version from 7.0.0 to 7.0.4 of this plugin, you should consider updating to the patched version, 7.0.5, immediately.

Description: Arbitrary File Upload
Affected Plugin:Comments – wpDiscuz
Plugin Slug: wpdiscuz
Affected Versions: 7.0.0 – 7.0.4
CVE ID: Pending.
CVSS Score: 10.0 (CRITICAL)
CVSS Vector:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Fully Patched Version: 7.0.5

wpDiscuz is a plugin designed to create responsive comment areas on WordPress installations. It allows users to discuss topics and easily customize their comments using a rich text editor. In the latest overhaul of the plugin, versions 7.x.x, they added the ability to include image attachments in comments which are uploaded to the site and included in the comments. Unfortunately, the implementation of this feature lacked security protections creating a critical vulnerability.

The wpDiscuz comments are intended to only allow image attachments. However, due to the file mime type detection functions that were used, the file type verification could easily be bypassed, allowing unauthenticated users the ability to upload any type of file, including PHP files.

Retrieving the Mime Type

The ‘getMimeType’ function used three different methods to determine a file’s mime type. The first check used mime_content_type, which determines a file’s type based on the file’s content. If that PHP function wasn’t available, it would use finfo_file, which also determines a file’s mime type based on the file’s content. Finally, if that function wasn’t available, then it would use wp_check_filetype, which is a WordPress-specific filetype check that determines a file’s mime type based on the file’s name and matches it against a built-in list of allowed file types.

Most files begin with several so-called “Magic Bytes” which are a specific signature that can be used to determine their Mime type. Unfortunately, due to how PHP processes files, it ignores everything in the file before the opening <?php tag. As such, the first two functions used could easily allow for files to be spoofed and appear as allowed image files simply by adding image-specific magic bytes. For example, a user could insert the magic-bytes for a .png file, 89 50 4E 47 0D 0A 1A 0A, at the beginning of a PHP file and fool the first two functions.

310311312313foreach ($files as $file) {$error = false;$extension = pathinfo($file["name"], PATHINFO_EXTENSION);$mimeType = $this->getMimeType($file, $extension);

376377378379380381382383384385386387388private function getMimeType($file, $extension) {$mimeType = "";if (function_exists("mime_content_type")) {$mimeType = mime_content_type($file["tmp_name"]);} elseif (function_exists("finfo_open") && function_exists("finfo_file")) {$finfo = finfo_open(FILEINFO_MIME_TYPE);$mimeType = finfo_file($finfo, $file["tmp_name"]);} elseif ($extension) {$matches = wp_check_filetype($file["name"], $this->options->content["wmuMimeTypes"]);$mimeType = empty($matches["type"]) ? "" : $matches["type"];}return $mimeType;}

Verifying Allowed File Types

The issue was escalated with the ‘isAllowedFileType’ function that did a check to see if the file was an allowed file type as it used the mime from the ‘getMimeType’ function. Due to the fact that the ‘getMimeType’ function used functions to obtain a file’s mime type based on file content, any file type could easily be spoofed to look like an allowed file type and pass this check.

368369370371372373374private function isAllowedFileType($mimeType) {$isAllowed = false;if (!empty($this->options->content["wmuMimeTypes"]) && is_array($this->options->content["wmuMimeTypes"])) {$isAllowed = in_array($mimeType, $this->options->content["wmuMimeTypes"]);}return $isAllowed;}

The Exploit Possibilities

This made it possible for attackers to create any file type and add image identifying features to files to pass the file content verification check. A PHP file attempting to bypass this verification could look something like this in a request:

------WebKitFormBoundaryXPeRFAXCS9qPc2sB
Content-Disposition: form-data; name="wmu_files[0]"; filename="myphpfile.php"
Content-Type: application/php

‰PNG

The file path location was returned as part of the request’s response, allowing a user to easily find the file’s location and access the file it was uploaded to the server. This meant that attackers could upload arbitrary PHP files and then access those files to trigger their execution on the server, achieving remote code execution.

If exploited, this vulnerability could allow an attacker to execute commands on your server and traverse your hosting account to further infect any sites hosted in the account with malicious code. This would effectively give the attacker complete control over every site on your server.