CVE-2019-5884: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: php/elFinder.class.php in elFinder before 2.1.45 leaks information if PHP's curl extension is enabled and safe_mode or open_basedir is not set.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 5.9
Published: 2019-01-10T08:29Z
Repository: https://github.com/Studio-42/elFinder
Language: PHP
Files changed: php/elFinder.class.php
Commit date: 2019-01-09 16:59:37 +0900
Commit message: [php:core:security] fix information leakage vulnerability

elFinder <= 2.1.44 PHP connector has high severity security
vulnerability to  information leakage. This vulnerability is affected on
environments in which the curl extension of PHP is enabled and safe_mode
or open_basedir is not set.

To fix this vulnerability with this commit.

We would like to express our special thanks to Ravindra Rajaram
(ravindra.rajaram@broadcom.com) and Hamsalekha Madiraju
(hamsalekha.madiraju@broadcom.com) who reported this vulnerability.

Diff: diff --git a/php/elFinder.class.php b/php/elFinder.class.php
index ee501dc11..7dac204a1 100644
--- a/php/elFinder.class.php
+++ b/php/elFinder.class.php
@@ -2393,12 +2393,15 @@ class elFinder
      * @rettval false  error
      * @author  Naoki Sawada
      **/
     protected function get_remote_contents(&$url, $timeout = 30, $redirect_max = 5, $ua = 'Mozilla/5.0', $fp = null)
     {
-        $method = (function_exists('curl_exec') && !ini_get('safe_mode') && !ini_get('open_basedir')) ? 'curl_get_contents' : 'fsock_get_contents';
-        return $this->$method($url, $timeout, $redirect_max, $ua, $fp);
+        if (preg_match('~^(?:ht|f)tps?://[-_.!\~*\'()a-z0-9;/?:\@&=+\$,%#\*]+~i', $url)) {
+            $method = (function_exists('curl_exec') && !ini_get('safe_mode') && !ini_get('open_basedir')) ? 'curl_get_contents' : 'fsock_get_contents';
+            return $this->$method($url, $timeout, $redirect_max, $ua, $fp);
+        }
+        return false;
     }
 
     /**
      * Get remote contents with cURL
      *
@@ -3035,23 +3038,24 @@ class elFinder
                     // check is data:
                     if (substr($url, 0, 5) === 'data:') {
                         list($data, $args['name'][$i]) = $this->parse_data_scheme($url, $extTable, $args);
                     } else {
                         $fp = fopen($tmpfname, 'wb');
-                        $data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp);
-                        // to check connection is aborted
-                        elFinder::checkAborted();
-                        $_name = preg_replace('~^.*?([^/#?]+)(?:\?.*)?(?:#.*)?$~', '$1', rawurldecode($url));
-                        // Check `Content-Disposition` response header
-                        if ($data && ($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) {
-                            if (preg_match('/filename\*=(?:([a-zA-Z0-9_-]+?)\'\')"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
-                                $_name = rawurldecode($m[2]);
-                                if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) {
-                                    $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]);
+                        if ($data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp)) {
+                            // to check connection is aborted
+                            elFinder::checkAborted();
+                            $_name = preg_replace('~^.*?([^/#?]+)(?:\?.*)?(?:#.*)?$~', '$1', rawurldecode($url));
+                            // Check `Content-Disposition` response header
+                            if ($data && ($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) {
+                                if (preg_match('/filename\*=(?:([a-zA-Z0-9_-]+?)\'\')"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
+                                    $_name = rawurldecode($m[2]);
+                                    if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) {
+                                        $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]);
+                                    }
+                                } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
+                                    $_name = rawurldecode($m[1]);
                                 }
-                            } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
-                                $_name = rawurldecode($m[1]);
                             }
                         }
                     }
                     if ($data) {
                         if (isset($args['name'][$i])) {

Vulnerable code:         $method = (function_exists('curl_exec') && !ini_get('safe_mode') && !ini_get('open_basedir')) ? 'curl_get_contents' : 'fsock_get_contents';
        return $this->$method($url, $timeout, $redirect_max, $ua, $fp);
                        $data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp);
                        // to check connection is aborted
                        elFinder::checkAborted();
                        $_name = preg_replace('~^.*?([^/#?]+)(?:\?.*)?(?:#.*)?$~', '$1', rawurldecode($url));
                        // Check `Content-Disposition` response header
                        if ($data && ($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) {
                            if (preg_match('/filename\*=(?:([a-zA-Z0-9_-]+?)\'\')"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
                                $_name = rawurldecode($m[2]);
                                if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) {
                                    $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]);
                            } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
                                $_name = rawurldecode($m[1]);
Fixed code:         if (preg_match('~^(?:ht|f)tps?://[-_.!\~*\'()a-z0-9;/?:\@&=+\$,%#\*]+~i', $url)) {
            $method = (function_exists('curl_exec') && !ini_get('safe_mode') && !ini_get('open_basedir')) ? 'curl_get_contents' : 'fsock_get_contents';
            return $this->$method($url, $timeout, $redirect_max, $ua, $fp);
        }
        return false;
                        if ($data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp)) {
                            // to check connection is aborted
                            elFinder::checkAborted();
                            $_name = preg_replace('~^.*?([^/#?]+)(?:\?.*)?(?:#.*)?$~', '$1', rawurldecode($url));
                            // Check `Content-Disposition` response header
                            if ($data && ($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) {
                                if (preg_match('/filename\*=(?:([a-zA-Z0-9_-]+?)\'\')"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
                                    $_name = rawurldecode($m[2]);
                                    if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) {
                                        $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]);
                                    }
                                } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
                                    $_name = rawurldecode($m[1]);