Recently, security researcher Dawid Golunski released an advisory describing a remote code execution vulnerability in the core of WordPress version 4.6 affecting the PHPMailer library. The vulnerability was published under CVE-2016-10033 and could be used by unauthenticated remote attackers against servers running WordPress with default web server configurations. In this post, we will summarize this advisory and explain the technical aspects of the vulnerability. To start, here is a short video of the exploit being executed by the researcher.
According to the WordPress Foundation, more than 40% of WordPress installations are still using versions 4.6 or older and could be vulnerable to this attack. If you are using WordPress, you should make sure to update to the latest version (4.8 at this time) as soon as possible!
Let’s get down to the technical details of the vulnerability. Here’s a piece of code from the pluggable.php file located inside the wp-includes folder:
As we can see in this mailer code, WordPress uses the SERVER_NAME header to set up the email domain when the wp_mail() is used to send an email. It is then used to populate the ‘from’ address in the e-mail.
According to Dawid’s advisory and the Apache documentation, the SERVER_NAME header can be easily manipulated on default configurations of the web server by using the Host header. Here is an example response from an Apache server after sending a fictitious Host header with a GET request:
To exploit this, attackers can use vectors which execute this mailer code like contact forms, password resets or email list subscription inputs. When using the reset password functionality in WordPress and tampering with the SERVER_NAME header, a vulnerable site would pass the value of your SERVER_NAME header directly to the sendmail mail transfer agent installed on the host. Using the manipulated Host header from above, here is what the sendmail command and its arguments would look like:
Arg no. 0 == [/usr/sbin/sendmail] Arg no. 1 == [-t] Arg no. 2 == [-i] Arg no. 3 == [[email protected]_case_host_header_value_here]
At this point, we know that externally supplied input (the domain portion of the from address) is being passed to an internal system command. For a would-be attacker, this is a great position to be in. Now the challenge becomes how to manipulate the input string in such a way that an arbitrary command could be passed in and executed by the underlying system. In this specific case, the researcher attempted to find a way to inject a space into the from email address parameter. This would provide the foundation for being able to separate an arbitrary command from the sendmail attributes.
There are checks that occur in the mailer code path to ensure this from email address is valid. However, Golunski found a way to bypass this validation by reviewing RFC 822 – the specification which defines email addresses and one of the oldest Internet standards. Although there is a newer version of this, RFC 2822 , not much has changed. In the RFC there is a description about comments in email addresses. Golunski discovered that with this forgotten functionality he could write comments as part of an email address, and that these comments could have spaces!
As a result, the following request would be considered valid and would not cause any errors on the web server:
POST /wordpress/wp-login.php?action=lostpassword HTTP/1.1Host: myserver(param1 exploit param2)
With a request like that, sendmail would receive the following parameters:
Arg no. 0 == [/usr/sbin/sendmail] Arg no. 1 == [-t] Arg no. 2 == [-i] Arg no. 3 == [[email protected](param1] Arg no. 4 == [exploit] Arg no. 5 == [param2)]
Now, an attacker could isolate a command string to execute, but since the Host header does not allow slashes, which are needed to insert directory paths to executables or files, there was more work required to do anything useful with this flaw. What this researcher found was that he could extract a slash from a default path variable called ‘$spool_directory’ using the substr function. Doing so would look like this:
So, to execute a command like `/usr/bin/touch /tmp/test` using this exploit, the input string would have to be transformed to
Now, one last hurdle is to remove the space character between the command, touch, and the path to the test file so that the string would be interpreted and executed as a single command rather than two. Using the same technique as before, the researcher was able to find a variable called ‘$tod_log’, which returns the current date with a space between the date and the time. Then the substring command could be used again to inject the desired space when the line was executed:
So, the final component of the Host header required to successfully execute this command during a password reset would look like this:
Not the easiest for humans to read, but no problem for servers! And with this proof of concept, you can imagine how it could quickly escalate from touching a file in a temp directory to make much more malicious changes.
Fortunately, this was found and reported by a security researcher and fixed by the WordPress core team before the details of the vulnerability were made public. Another good reminder to stay up-to-date on WordPress core, as well as all of your plugins and themes!