Skip to content

Commit 06aae8b

Browse files
committed
Merge PR PHPMailer#930 from @Zanaxer
2 parents 8d68507 + 833c35f commit 06aae8b

File tree

1 file changed

+44
-9
lines changed

1 file changed

+44
-9
lines changed

class.phpmailer.php

+44-9
Original file line numberDiff line numberDiff line change
@@ -1364,21 +1364,24 @@ public function postSend()
13641364
*/
13651365
protected function sendmailSend($header, $body)
13661366
{
1367-
// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped
1368-
// by escapeshellcmd when popen is called due to safe mode.
1369-
if (!empty($this->Sender) && !ini_get('safe_mode')) {
1367+
// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1368+
if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
13701369
if ($this->Mailer == 'qmail') {
1371-
$sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1370+
$sendmailFmt = '%s -f%s';
13721371
} else {
1373-
$sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
1372+
$sendmailFmt = '%s -oi -f%s -t';
13741373
}
13751374
} else {
13761375
if ($this->Mailer == 'qmail') {
1377-
$sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
1376+
$sendmailFmt = '%s';
13781377
} else {
1379-
$sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
1378+
$sendmailFmt = '%s -oi -t';
13801379
}
13811380
}
1381+
1382+
// TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing.
1383+
$sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1384+
13821385
if ($this->SingleTo) {
13831386
foreach ($this->SingleToArray as $toAddr) {
13841387
if (!@$mail = popen($sendmail, 'w')) {
@@ -1424,6 +1427,38 @@ protected function sendmailSend($header, $body)
14241427
return true;
14251428
}
14261429

1430+
/**
1431+
* Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
1432+
*
1433+
* Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows.
1434+
* @param string $string The string to be validated
1435+
* @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report
1436+
* @access protected
1437+
* @return boolean
1438+
*/
1439+
protected static function isShellSafe($string)
1440+
{
1441+
// Future-proof
1442+
if (escapeshellcmd($string) !== $string or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))) {
1443+
return false;
1444+
}
1445+
1446+
$length = strlen($string);
1447+
1448+
for ($i = 0; $i < $length; $i++) {
1449+
$c = $string[$i];
1450+
1451+
// All other characters have a special meaning in at least one common shell, including = and +.
1452+
// Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here.
1453+
// Note that this does permit non-Latin alphanumeric characters based on the current locale.
1454+
if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1455+
return false;
1456+
}
1457+
}
1458+
1459+
return true;
1460+
}
1461+
14271462
/**
14281463
* Send mail using the PHP mail() function.
14291464
* @param string $header The message headers
@@ -1445,8 +1480,8 @@ protected function mailSend($header, $body)
14451480
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
14461481
if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
14471482
// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
1448-
if (escapeshellcmd($this->Sender) === $this->Sender && in_array(escapeshellarg($this->Sender), array("'$this->Sender'", "\"$this->Sender\""))) {
1449-
$params = sprintf('-f%s', escapeshellarg($this->Sender));
1483+
if (self::isShellSafe($this->Sender)) {
1484+
$params = sprintf('-f%s', $this->Sender);
14501485
}
14511486
}
14521487
if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {

0 commit comments

Comments
 (0)