由于PHPCMSV9文件attachments.php的未验证上传用户权限,可以上传文件(仅图片)。加上其他文件存在可以截断的本地包含漏洞,导致包含任意文件并获取webshell 文件\phpcms\modules\attachment\attachments.php <code>public function crop_upload() { if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $pic = $GLOBALS["HTTP_RAW_POST_DATA"]; …… file_put_contents($this->upload_path.$filepath.$new_file, $pic);</code> 通过调用该函数可以上传图片文件,程序最后将上传后的图片详细地址输出给用户 文件\phpcms\modules\comment\index.php <code>$this->commentid = isset($_GET['commentid']) && trim(urldecode($_GET['commentid'])) ? trim(urldecode($_GET['commentid'])) : $this->_show_msg(L('illegal_parameters')); $this->commentid = safe_replace($this->commentid);</code> 变量$_GET['commentid']先经过urldecode函数做url解码,再经过安全函数safe_replace过滤。 函数safe_replace在文件\phpcms\libs\functions\ global.func.php <code>function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string);...
由于PHPCMSV9文件attachments.php的未验证上传用户权限,可以上传文件(仅图片)。加上其他文件存在可以截断的本地包含漏洞,导致包含任意文件并获取webshell 文件\phpcms\modules\attachment\attachments.php <code>public function crop_upload() { if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $pic = $GLOBALS["HTTP_RAW_POST_DATA"]; …… file_put_contents($this->upload_path.$filepath.$new_file, $pic);</code> 通过调用该函数可以上传图片文件,程序最后将上传后的图片详细地址输出给用户 文件\phpcms\modules\comment\index.php <code>$this->commentid = isset($_GET['commentid']) && trim(urldecode($_GET['commentid'])) ? trim(urldecode($_GET['commentid'])) : $this->_show_msg(L('illegal_parameters')); $this->commentid = safe_replace($this->commentid);</code> 变量$_GET['commentid']先经过urldecode函数做url解码,再经过安全函数safe_replace过滤。 函数safe_replace在文件\phpcms\libs\functions\ global.func.php <code>function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string); $string = str_replace('*','',$string); $string = str_replace('"','&quot;',$string); $string = str_replace("'",'',$string); $string = str_replace('"','',$string); $string = str_replace(';','',$string); $string = str_replace('<','&lt;',$string); $string = str_replace('>','&gt;',$string); $string = str_replace("{",'',$string); $string = str_replace('}','',$string); $string = str_replace('\\','',$string); return $string; }</code> 变量$_GET['commentid'] 经过函数urldecode解码,可以绕过gpc对特殊字符的过滤。虽然后面经过安全函数safe_replace的过滤,但最终没有过滤\0 在相同文件\phpcms\modules\comment\index.php中, <code>public function post() { …… if (!$data = get_comment_api($this->commentid)) { $this->_show_msg(L('illegal_parameters')); } else { $title = $data['title']; $url = $data['url']; unset($data); }</code> 变量$this->commentid进入到函数get_comment_api中, 函数定义在文件\phpcms\modules\comment\functions\global.func.php中 <code>function get_comment_api($commentid) { list($modules, $contentid, $siteid) = id_decode($commentid); if (empty($modules) || empty($siteid) || empty($contentid)) { return false; } $comment_api = ''; $module = explode('_', $modules); $comment_api = pc_base::load_app_class('comment_api', $module[0]); if (empty($comment_api)) return false; return $comment_api->get_info($modules, $contentid, $siteid); }</code> 变量$commentid经过分割,$module[0]进入到函数load_app_class 在文件\phpcms\base.php可以找到load_app_class <code>public static function load_app_class($classname, $m = '', $initialize = 1) { $m = empty($m) && defined('ROUTE_M') ? ROUTE_M : $m; if (empty($m)) return false; return self::_load_class($classname, 'modules'.DIRECTORY_SEPARATOR.$m.DIRECTORY_SEPARATOR.'classes', $initialize); }</code> 变量$module[0]进入_load_class函数,代码如下: <code>private static function _load_class($classname, $path = '', $initialize = 1) { static $classes = array(); if (empty($path)) $path = 'libs'.DIRECTORY_SEPARATOR.'classes'; $key = md5($path.$classname); if (isset($classes[$key])) { if (!empty($classes[$key])) { return $classes[$key]; } else { return true; } } if (file_exists(PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.'.class.php')) { include PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.'.class.php'; </code> 最终产生本地包含漏洞,且变量$classname是可以保留最初的截断00 由于PHPCMSV9文件attachments.php的未验证上传用户权限,可以上传文件(仅图片)。加上其他文件存在可以截断的本地包含漏洞,导致包含任意文件并获取webshell 文件\phpcms\modules\attachment\attachments.php <pre class="prettyprint linenums">public function crop_upload() { if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $pic = $GLOBALS["HTTP_RAW_POST_DATA"]; …… file_put_contents($this->upload_path.$filepath.$new_file, $pic);</pre> 通过调用该函数可以上传图片文件,程序最后将上传后的图片详细地址输出给用户 文件\phpcms\modules\comment\index.php <pre class="prettyprint linenums">$this->commentid = isset($_GET['commentid']) && trim(urldecode($_GET['commentid'])) ? trim(urldecode($_GET['commentid'])) : $this->_show_msg(L('illegal_parameters')); $this->commentid = safe_replace($this->commentid);</pre> 变量$_GET['commentid']先经过urldecode函数做url解码,再经过安全函数safe_replace过滤。 函数safe_replace在文件\phpcms\libs\functions\ global.func.php <pre class="prettyprint linenums">function safe_replace($string) { $string = str_replace('%20','',$string); $string = str_replace('%27','',$string); $string = str_replace('%2527','',$string); $string = str_replace('*','',$string); $string = str_replace('"','&quot;',$string); $string = str_replace("'",'',$string); $string = str_replace('"','',$string); $string = str_replace(';','',$string); $string = str_replace('<','&lt;',$string); $string = str_replace('>','&gt;',$string); $string = str_replace("{",'',$string); $string = str_replace('}','',$string); $string = str_replace('\\','',$string); return $string; }</pre> 变量$_GET['commentid'] 经过函数urldecode解码,可以绕过gpc对特殊字符的过滤。虽然后面经过安全函数safe_replace的过滤,但最终没有过滤\0 在相同文件\phpcms\modules\comment\index.php中, <pre class="prettyprint linenums">public function post() { …… if (!$data = get_comment_api($this->commentid)) { $this->_show_msg(L('illegal_parameters')); } else { $title = $data['title']; $url = $data['url']; unset($data); }</pre> 变量$this->commentid进入到函数get_comment_api中, 函数定义在文件\phpcms\modules\comment\functions\global.func.php中 <pre class="prettyprint linenums">function get_comment_api($commentid) { list($modules, $contentid, $siteid) = id_decode($commentid); if (empty($modules) || empty($siteid) || empty($contentid)) { return false; } $comment_api = ''; $module = explode('_', $modules); $comment_api = pc_base::load_app_class('comment_api', $module[0]); if (empty($comment_api)) return false; return $comment_api->get_info($modules, $contentid, $siteid); }</pre> 变量$commentid经过分割,$module[0]进入到函数load_app_class 在文件\phpcms\base.php可以找到load_app_class <pre class="prettyprint linenums">public static function load_app_class($classname, $m = '', $initialize = 1) { $m = empty($m) && defined('ROUTE_M') ? ROUTE_M : $m; if (empty($m)) return false; return self::_load_class($classname, 'modules'.DIRECTORY_SEPARATOR.$m.DIRECTORY_SEPARATOR.'classes', $initialize); }</pre> 变量$module[0]进入_load_class函数,代码如下: <pre class="prettyprint linenums">private static function _load_class($classname, $path = '', $initialize = 1) { static $classes = array(); if (empty($path)) $path = 'libs'.DIRECTORY_SEPARATOR.'classes'; $key = md5($path.$classname); if (isset($classes[$key])) { if (!empty($classes[$key])) { return $classes[$key]; } else { return true; } } if (file_exists(PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.'.class.php')) { include PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.'.class.php'; </pre> 最终产生本地包含漏洞,且变量$classname是可以保留最初的截断00 PHPCMS V9.1.8 (20111014) sebug 临时解决方案: 1、过滤变量$_GET['commentid'] 2、安全函数safe_replace增加对00字符的过滤 厂商补丁: PHPCMS ------- 目前厂商已经提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本: http://bbs.phpcms.cn/thread-444632-1-1.html