About the CVE 2016 10033 and CVE 2016 10045 vulnerabilities
Clone this wiki locally
- The script is using PHPMailer's default
isMail()transport, i.e. using PHP's built-in
- The 'From' address is set from user input.
Senderproperty is not set explicitly.
- The server is not running the postfix mail server
In the absence of a preset
Sender property, it is copied from the from address. This in turn is built into a string, prefixed with
-f to designate a sender address, and passed into the
$additional_parameters parameter of the PHP
All addresses used by PHPMailer are validated before being used, however, it's possible to construct a valid email address that also constitutes an executable command when passed to the shell via
This vulnerability constitutes CVE-2016-10033, and was thought to be resolved by applying
escapeshellarg() to the address, and released as PHPMailer 5.2.20, with a subsequent cleanup in PHPMailer 5.2.21.
The documentation for
mail() mentions that
escapeshellcmd() is applied internally to the command generated by
mail(), and that 'dangerous' characters should be escaped. Unfortunately this clashes with what
escapeshellarg() does, and the nested combination of
escapeshellcmd(escapeshellarg($address)) can result in a crafted address breaking out of the escaping, resulting in an executable command again. This was also spotted by Dawid Golunski (advisory) and reported as CVE-2016-10045. Unhelpfully, an exploit for this was posted on an open mailing list the same day, making this a 0-day vulnerability.
This is a much more insidious problem because it's really a problem with PHP internals, and the only reliable mitigation is to prevent use of valid addresses that might also be exploits, which requires breaking RFC compliance for sender addresses. The
escapeshellarg functions make assumptions about the underlying shell environment (for example what character it uses for escaping, which may not be
\, or what character set is in use), so their use cannot be considered safe especially across platforms - the only safe route is to apply severe restrictions to the sender address in this context. A patch to this effect was provided by @Zenexer and released in PHPMailer 5.2.20. @Zenexer also provided a technical description of the problems surrounding shell escaping in PHP.
A proper fix for this would be to rewrite the PHP mail function so that it treats
$additional_parameters as an array of individual configuration elements that can be processed separately, not a string, or more thoroughly, to not invoke
sendmail via a shell at all, avoiding escaping issues altogether.
You're safe if...
You need to be doing one key thing wrong in order to be vulnerable to this attack: using a user-supplied address as the From address, for example:
If you're not doing that, you've nothing to worry about, but unfortunately this is quite a common pattern on naïve 'contact us' forms (see Stack Overflow for many examples) because it means you can reply to the message and it will go directly to the supposed sender. However, this is bad practice because it's forging the from address, and so it will likely fail SPF and DMARC checks and you will have difficulty getting messages delivered. The correct way to do this is along the lines of:
$mail->setFrom('email@example.com'); //Send from a fixed, valid address in your own domain, perhaps one that allows you to easily identify that it originated on your contact form $mail->addAddress('firstname.lastname@example.org'); //Send to a fixed, valid address in your own domain $mail->addReplyTo($_POST['email']); //The submitter's address (supposedly) - this is automatically validated before it's accepted so you should check the return value from this function
You are also safe if you're using PHPMailer's SMTP transport (i.e. you call
$mail->isSMTP() in your code), as that transport does not execute shell commands.
You're indirectly protected if you use postfix as your mail server (the default in many Linux distros), because it lacks support for sendmail's
-X option that permits the creation of executable commands. However, you shouldn't rely on this, as it's possible that other exploits for the same vulnerability will affect postfix.
Don't think you're safe if...
You're not using PHPMailer? Both of these vulnerabilities occur in other popular PHP email libraries and applications too - for example Swiftmailer, zend_mail, and roundcube, and there may be many more.
How to avoid issues in future?
CVE-2016-10045 particular has enormous implications well beyond PHPMailer, so check your sources, and help their maintainers spot and fix problems like this before they escape into the wild. There may be other exploits found for
mail() (keep an eye on Dawid Golunski's white paper on the subject), so the most important thing is to make sure you stay up to date with all your packages, not just PHPMailer.