1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
From: Markus Koschany <apo@debian.org>
Date: Sat, 25 Feb 2017 19:00:40 +0100
Subject: CVE-2017-5223
It was discovered that there was a local file disclosure vulnerability in
libphp-phpmailer, a email transfer class for PHP, where insufficient parsing of
HTML messages could potentially be used by attacker to read a local file.
Bug-Debian: https://bugs.debian.org/853232
Origin: https://github.com/PHPMailer/PHPMailer/commit/ad4cb09682682da2217799a0c521d4cdc6753402
---
class.phpmailer.php | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/class.phpmailer.php b/class.phpmailer.php
index 8aa4752..5c43d1b 100644
--- a/class.phpmailer.php
+++ b/class.phpmailer.php
@@ -2418,6 +2418,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.
@@ -2943,6 +2944,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.
@@ -3306,10 +3308,14 @@ class PHPMailer
* Create a message from an HTML string.
* Automatically makes modifications for inline images and backgrounds
* and creates a plain-text version by converting the HTML.
- * Overwrites any existing values in $this->Body and $this->AltBody
+ * Overwrites any existing values in Body and AltBody
+ * Do not source $message content from user input!
+ * $basedir is prepended when handling relative URLs, e.g. <img src="/images/a.png"> and must not be empty
+ * 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 baseline directory for path
+ * @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
@@ -3318,6 +3324,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)) {
@@ -3335,18 +3345,24 @@ class PHPMailer
$message
);
}
- } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[A-z]+://#', $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 .= '/';
}
|