diff --git a/plugin/PHPMailer/VERSION b/plugin/PHPMailer/VERSION index 1c26b6f22..07b26572f 100644 --- a/plugin/PHPMailer/VERSION +++ b/plugin/PHPMailer/VERSION @@ -1 +1 @@ -5.2.19 \ No newline at end of file +5.2.22 diff --git a/plugin/PHPMailer/class.phpmailer.php b/plugin/PHPMailer/class.phpmailer.php index 6afcf9ae9..477ee826e 100644 --- a/plugin/PHPMailer/class.phpmailer.php +++ b/plugin/PHPMailer/class.phpmailer.php @@ -31,7 +31,7 @@ class PHPMailer * The PHPMailer Version number. * @var string */ - public $Version = '5.2.19'; + public $Version = '5.2.22'; /** * Email priority. @@ -1364,19 +1364,24 @@ class PHPMailer */ protected function sendmailSend($header, $body) { - if (!empty($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)) { if ($this->Mailer == 'qmail') { - $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + $sendmailFmt = '%s -f%s'; } else { - $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + $sendmailFmt = '%s -oi -f%s -t'; } } else { if ($this->Mailer == 'qmail') { - $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail)); + $sendmailFmt = '%s'; } else { - $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail)); + $sendmailFmt = '%s -oi -t'; } } + + // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing. + $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + if ($this->SingleTo) { foreach ($this->SingleToArray as $toAddr) { if (!@$mail = popen($sendmail, 'w')) { @@ -1422,6 +1427,40 @@ class PHPMailer return true; } + /** + * 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; + } + /** * Send mail using the PHP mail() function. * @param string $header The message headers @@ -1442,7 +1481,10 @@ class PHPMailer $params = null; //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { - $params = sprintf('-f%s', escapeshellarg($this->Sender)); + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } } if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) { $old_from = ini_get('sendmail_from'); @@ -2450,6 +2492,7 @@ class PHPMailer /** * Add an attachment from a path on the filesystem. + * Never use a user-supplied path to a file! * Returns false if the file could not be found or read. * @param string $path Path to the attachment. * @param string $name Overrides the attachment name. @@ -2975,6 +3018,7 @@ class PHPMailer * displayed inline with the message, not just attached for download. * This is used in HTML messages that embed the images * the HTML refers to using the $cid value. + * Never use a user-supplied path to a file! * @param string $path Path to the attachment. * @param string $cid Content ID of the attachment; Use this to reference * the content when using an embedded image in HTML. @@ -3338,12 +3382,14 @@ class PHPMailer * Create a message body from an HTML string. * Automatically inlines images and creates a plain-text version by converting the HTML, * overwriting any existing values in Body and AltBody. - * $basedir is used when handling relative image paths, e.g. + * Do not source $message content from user input! + * $basedir is prepended when handling relative URLs, e.g. and must not be empty * will look for an image file in $basedir/images/a.png and convert it to inline. - * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself. + * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email) + * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly. * @access public * @param string $message HTML message string - * @param string $basedir base directory for relative paths to images + * @param string $basedir Absolute path to a base directory to prepend to relative paths to images * @param boolean|callable $advanced Whether to use the internal HTML to text converter * or your own custom converter @see PHPMailer::html2text() * @return string $message The transformed message Body @@ -3352,6 +3398,10 @@ class PHPMailer { preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); if (array_key_exists(2, $images)) { + if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { + // Ensure $basedir has a trailing / + $basedir .= '/'; + } foreach ($images[2] as $imgindex => $url) { // Convert data URIs into embedded images if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { @@ -3369,18 +3419,24 @@ class PHPMailer $message ); } - } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) { - // Do not change urls for absolute images (thanks to corvuscorax) + continue; + } + if ( + // Only process relative URLs if a basedir is provided (i.e. no absolute local paths) + !empty($basedir) + // Ignore URLs containing parent dir traversal (..) + && (strpos($url, '..') === false) // Do not change urls that are already inline images + && substr($url, 0, 4) !== 'cid:' + // Do not change absolute URLs, including anonymous protocol + && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url) + ) { $filename = basename($url); $directory = dirname($url); if ($directory == '.') { $directory = ''; } $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 - if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { - $basedir .= '/'; - } if (strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; } diff --git a/plugin/PHPMailer/class.pop3.php b/plugin/PHPMailer/class.pop3.php index 32d614b35..f10e688e3 100644 --- a/plugin/PHPMailer/class.pop3.php +++ b/plugin/PHPMailer/class.pop3.php @@ -34,7 +34,7 @@ class POP3 * @var string * @access public */ - public $Version = '5.2.19'; + public $Version = '5.2.22'; /** * Default POP3 port number. diff --git a/plugin/PHPMailer/class.smtp.php b/plugin/PHPMailer/class.smtp.php index 04ced6581..89321171b 100644 --- a/plugin/PHPMailer/class.smtp.php +++ b/plugin/PHPMailer/class.smtp.php @@ -30,7 +30,7 @@ class SMTP * The PHPMailer SMTP version number. * @var string */ - const VERSION = '5.2.19'; + const VERSION = '5.2.22'; /** * SMTP line break constant. @@ -81,7 +81,7 @@ class SMTP * @deprecated Use the `VERSION` constant instead * @see SMTP::VERSION */ - public $Version = '5.2.19'; + public $Version = '5.2.22'; /** * SMTP server port number. diff --git a/plugin/PHPMailer/examples/contactform.phps b/plugin/PHPMailer/examples/contactform.phps new file mode 100644 index 000000000..d85e20456 --- /dev/null +++ b/plugin/PHPMailer/examples/contactform.phps @@ -0,0 +1,71 @@ +isSMTP(); + $mail->Host = 'localhost'; + $mail->Port = 25; + + //Use a fixed address in your own domain as the from address + //**DO NOT** use the submitter's address here as it will be forgery + //and will cause your messages to fail SPF checks + $mail->setFrom('from@example.com', 'First Last'); + //Send the message to yourself, or whoever should receive contact for submissions + $mail->addAddress('whoto@example.com', 'John Doe'); + //Put the submitter's address in a reply-to header + //This will fail if the address provided is invalid, + //in which case we should ignore the whole request + if ($mail->addReplyTo($_POST['email'], $_POST['name'])) { + $mail->Subject = 'PHPMailer contact form'; + //Keep it simple - don't use HTML + $mail->isHTML(false); + //Build a simple message body + $mail->Body = <<send()) { + //The reason for failing to send will be in $mail->ErrorInfo + //but you shouldn't display errors to users - process the error, log it on your server. + $msg = 'Sorry, something went wrong. Please try again later.'; + } else { + $msg = 'Message sent! Thanks for contacting us.'; + } + } else { + $msg = 'Invalid email address, message ignored.'; + } +} +?> + + + + + Contact form + + +

Contact us

+$msg"; +} ?> +
+
+
+
+ +
+ + diff --git a/plugin/PHPMailer/examples/contentsutf8.html b/plugin/PHPMailer/examples/contentsutf8.html index 81a202405..035d10c8d 100644 --- a/plugin/PHPMailer/examples/contentsutf8.html +++ b/plugin/PHPMailer/examples/contentsutf8.html @@ -15,6 +15,7 @@

Russian text: Пустое тело сообщения

Armenian text: Հաղորդագրությունը դատարկ է

Czech text: Prázdné tělo zprávy

+

Emoji: 😂 🦄 💥 📤 📧

diff --git a/plugin/PHPMailer/examples/scripts/XRegExp.js b/plugin/PHPMailer/examples/scripts/XRegExp.js index ebdb9c948..feb66798a 100644 --- a/plugin/PHPMailer/examples/scripts/XRegExp.js +++ b/plugin/PHPMailer/examples/scripts/XRegExp.js @@ -259,7 +259,7 @@ if (XRegExp) { //--------------------------------- - // Overriden native methods + // Overridden native methods //--------------------------------- // Adds named capture support (with backreferences returned as `result.name`), and fixes two diff --git a/plugin/PHPMailer/examples/send_file_upload.phps b/plugin/PHPMailer/examples/send_file_upload.phps index 3004c7628..ab60fd104 100644 --- a/plugin/PHPMailer/examples/send_file_upload.phps +++ b/plugin/PHPMailer/examples/send_file_upload.phps @@ -17,7 +17,7 @@ if (array_key_exists('userfile', $_FILES)) { $mail->setFrom('from@example.com', 'First Last'); $mail->addAddress('whoto@example.com', 'John Doe'); $mail->Subject = 'PHPMailer file sender'; - $mail->msgHTML("My message body"); + $mail->Body = 'My message body'; // Attach the uploaded file $mail->addAttachment($uploadfile, 'My uploaded file'); if (!$mail->send()) { diff --git a/plugin/PHPMailer/examples/send_multiple_file_upload.phps b/plugin/PHPMailer/examples/send_multiple_file_upload.phps index ddb761468..72f21153e 100644 --- a/plugin/PHPMailer/examples/send_multiple_file_upload.phps +++ b/plugin/PHPMailer/examples/send_multiple_file_upload.phps @@ -12,7 +12,7 @@ if (array_key_exists('userfile', $_FILES)) { $mail->setFrom('from@example.com', 'First Last'); $mail->addAddress('whoto@example.com', 'John Doe'); $mail->Subject = 'PHPMailer file sender'; - $mail->msgHTML('My message body'); + $mail->Body = 'My message body'; //Attach multiple files one by one for ($ct = 0; $ct < count($_FILES['userfile']['tmp_name']); $ct++) { $uploadfile = tempnam(sys_get_temp_dir(), sha1($_FILES['userfile']['name'][$ct])); diff --git a/plugin/PHPMailer/extras/htmlfilter.php b/plugin/PHPMailer/extras/htmlfilter.php index 7727487e5..a86ef579d 100644 --- a/plugin/PHPMailer/extras/htmlfilter.php +++ b/plugin/PHPMailer/extras/htmlfilter.php @@ -433,7 +433,7 @@ function tln_getnxtag($body, $offset) * * @param string $attvalue the by-ref value to check. * @param string $regex the regular expression to check against. - * @param boolean $hex whether the entites are hexadecimal. + * @param boolean $hex whether the entities are hexadecimal. * @return boolean True or False depending on whether there were matches. */ function tln_deent(&$attvalue, $regex, $hex = false) @@ -772,7 +772,7 @@ function tln_fixstyle($body, $pos, $trans_image_path, $block_external_images) tln_defang($contentTemp); tln_unspace($contentTemp); - $match = Array('/\/\*.*\*\//', + $match = array('/\/\*.*\*\//', '/expression/i', '/behaviou*r/i', '/binding/i', @@ -780,7 +780,7 @@ function tln_fixstyle($body, $pos, $trans_image_path, $block_external_images) '/javascript/i', '/script/i', '/position/i'); - $replace = Array('','idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', ''); + $replace = array('','idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', 'idiocy', ''); $contentNew = preg_replace($match, $replace, $contentTemp); if ($contentNew !== $contentTemp) { $content = $contentNew;