Vulnerability: 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.
Vulnerability ID: CVE-2019-5884
CWE: CWE-200
Severity score: 2.9
Project: https://github.com/Studio-42/elFinder
Published: 2019-01-10
File: php/elFinder.class.php
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.
Commit author: nao-pon

Vulnerable version (before fix):
 protected function abort($args = array())      **/     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);     }      /** protected function upload($args)                         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]);                                 }                             } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {                                 $_name = rawurldecode($m[1]);                             }                         }                     }

Fixed version (after fix):
 protected function abort($args = array())      **/     protected function get_remote_contents(&$url, $timeout = 30, $redirect_max = 5, $ua = 'Mozilla/5.0', $fp = null)     {         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;     }      /** protected function upload($args)                         list($data, $args['name'][$i]) = $this->parse_data_scheme($url, $extTable, $args);                     } else {                         $fp = fopen($tmpfname, 'wb');                         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]);                                 }                             }                         }                     }

Patch:
patch: @@ -2395,8 +2395,11 @@ protected function abort($args = array())
      **/
     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;
     }
 
     /**
@@ -3037,19 +3040,20 @@ protected function upload($args)
                         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]);
                             }
                         }
                     }
path: php/elFinder.class.php