From 60d390f52e73b29f215301bcf978c56ecae5d3c5 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 17 Sep 2018 00:48:47 +0900 Subject: [PATCH] Initial mitigations for #1088 #1089 --- classes/context/Context.class.php | 22 +++++---- classes/security/UploadFileFilter.class.php | 54 ++++++++++++++++++++- modules/file/file.controller.php | 2 +- modules/member/member.admin.controller.php | 6 +-- modules/member/member.controller.php | 18 +++---- 5 files changed, 79 insertions(+), 23 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index ee68ccb23..86c33c211 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -1261,8 +1261,9 @@ class Context $tmp_name = $val['tmp_name']; if(!is_array($tmp_name)) { - if(!$tmp_name || !is_uploaded_file($tmp_name) || $val['size'] <= 0) + if(!UploadFileFilter::check($tmp_name, $val['name'])) { + unset($_FILES[$key]); continue; } $val['name'] = escape($val['name'], false); @@ -1275,16 +1276,19 @@ class Context $files = array(); foreach ($tmp_name as $i => $j) { - if($val['size'][$i] > 0) + if(!UploadFileFilter::check($val['tmp_name'][$i], $val['name'][$i])) { - $file = array(); - $file['name'] = $val['name'][$i]; - $file['type'] = $val['type'][$i]; - $file['tmp_name'] = $val['tmp_name'][$i]; - $file['error'] = $val['error'][$i]; - $file['size'] = $val['size'][$i]; - $files[] = $file; + $files = array(); + unset($_FILES[$key]); + break; } + $file = array(); + $file['name'] = $val['name'][$i]; + $file['type'] = $val['type'][$i]; + $file['tmp_name'] = $val['tmp_name'][$i]; + $file['error'] = $val['error'][$i]; + $file['size'] = $val['size'][$i]; + $files[] = $file; } if(count($files)) { diff --git a/classes/security/UploadFileFilter.class.php b/classes/security/UploadFileFilter.class.php index b19bd6889..1b3b73a34 100644 --- a/classes/security/UploadFileFilter.class.php +++ b/classes/security/UploadFileFilter.class.php @@ -3,8 +3,60 @@ class UploadFileFilter { - public function check($file) + /** + * Generic checker + * + * @param string $file + * @param string $filename + * @return bool + */ + public static function check($file, $filename = null) { + // Return error if the file is not uploaded. + if (!$file || !file_exists($file) || !is_uploaded_file($file)) + { + return false; + } + + // Return error if the file size is zero. + if (!filesize($file)) + { + return false; + } + + // Get the extension. + $ext = $filename ? strtolower(substr(strrchr($filename, '.'), 1)) : ''; + + // Check SVG files. + if ($ext === 'svg' && !self::_checkSVG($file)) + { + return false; + } + + // Return true if everything is OK. + return true; + } + + /** + * Check SVG file for XSS or SSRF vulnerabilities (#1088, #1089) + * + * @param string $file + * @return bool + */ + protected static function _checkSVG($file) + { + $content = file_get_contents($file); + + if (preg_match('/xlink:href\s*=\s*"(?!data:)/i', $content)) + { + return false; + } + + if (preg_match('/