This patch is based on 2 commits containing fix for CVE-2016-10045 and CVE-2016-10033: https://github.com/PHPMailer/PHPMailer/commit/9743ff5c7ee16e8d49187bd2e11149afb9485eae https://github.com/PHPMailer/PHPMailer/commit/833c35fe39715c3d01934508987e97af1fbc1ba0 which were adjusted to PHPMailer_5.2.4 source code diff -ru PHPMailer_5.2.4/class.phpmailer.php.orig PHPMailer_5.2.4/class.phpmailer.php --- PHPMailer_5.2.4/class.phpmailer.php.orig +++ PHPMailer_5.2.4/class.phpmailer.php @@ -861,6 +861,38 @@ } /** + * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. + * + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * @param string $string The string to be validated + * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report + * @access protected + * @return boolean + */ + protected static function isShellSafe($string) + { + // Future-proof + if (escapeshellcmd($string) !== $string or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))) { + return false; + } + + $length = strlen($string); + + for ($i = 0; $i < $length; $i++) { + $c = $string[$i]; + + // All other characters have a special meaning in at least one common shell, including = and +. + // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + // Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** * Sends mail using the $Sendmail program. * @param string $header The message headers * @param string $body The message body @@ -869,8 +901,10 @@ * @return bool */ protected function SendmailSend($header, $body) { - if ($this->Sender != '') { - $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) and self::isShellSafe($this->Sender)) { + // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing. + $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), $this->Sender); } else { $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); } @@ -925,7 +959,9 @@ if (empty($this->Sender)) { $params = "-oi "; } else { - $params = sprintf("-oi -f%s", $this->Sender); + if (self::isShellSafe($this->Sender)) { + $params = sprintf("-oi -f%s", $this->Sender); + } } if ($this->Sender != '' and !ini_get('safe_mode')) { $old_from = ini_get('sendmail_from');