Phpcms v9漏洞分析

最近研究源码审计相关知识,会抓起以前开源的CMS漏洞进行研究,昨天偶然看见了这个PHPCMS的漏洞,就准备分析研究一番,最开始本来想直接从源头对代码进行静态分析,但是发现本身对PHPCMS架构不是很熟悉,导致很难定位代码的位置,***就采用动态调试&静态分析的方式对漏洞的触发进行分析,下面进入正题。

1. 漏洞触发代码定位

通过漏洞的POC(/phpcms/index.php?m=member&c=index&a=register&siteid=1 )判断,漏洞触发点的入口位于/phpcms/modules/member/index.php文件中的register()方法中,在代码中插入一些echo函数,观察输出(见下)的变化。从下面的结果变化可知,img标签的src属性是在执行完下面的get()函数:

  1. $user_model_info = $member_input->get($_POST['info']) 

后发生变化,因此基本可以确定,漏洞的触发点就是位于这个函数中。

2. 定位member_input->get()跟进分析

跟进该函数,该函数位于/phpcms/modules/member/fields/member_input.class.php文件中,此处本来还想故技重施,在该方法中对代码进行插桩,但是发现插桩后的居然无法打印到页面上,没辙(原因望各位大神指点一二),只能对代码进行一行行推敲,先把代码贴上,方便分析:

  1. function get($data) { 
  2.     $this->data = $data = trim_script($data); 
  3.     $model_cache = getcache('member_model', 'commons'); 
  4.     $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename']; 
  5.     $info = array(); 
  6.     $debar_filed = array('catid','title','style','thumb','status','islink','description'); 
  7.     if(is_array($data)) { 
  8.         foreach($data as $field=>$value) { 
  9.             if($data['islink']==1 && !in_array($field,$debar_filed)) continue; 
  10.             $field = safe_replace($field); 
  11.             $name = $this->fields[$field]['name']; 
  12.             $minlength = $this->fields[$field]['minlength']; 
  13.             $maxlength = $this->fields[$field]['maxlength']; 
  14.             $pattern = $this->fields[$field]['pattern']; 
  15.             $errortips = $this->fields[$field]['errortips']; 
  16.             if(empty($errortips)) $errortips = "$name 不符合要求!"
  17.             $length = empty($value) ? 0 : strlen($value); 
  18.             if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!"); 
  19.             if (!array_key_exists($field, $this->fields)) showmessage('模型中不存在'.$field.'字段'); 
  20.             if($maxlength && $length > $maxlength && !$isimport) { 
  21.                 showmessage("$name 不得超过 $maxlength 个字符!"); 
  22.             } else { 
  23.                 str_cut($value, $maxlength); 
  24.             } 
  25.             if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips); 
  26.                         if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!"); 
  27.             $func = $this->fields[$field]['formtype']; 
  28.             if(method_exists($this, $func)) $value = $this->$func($field, $value); 
  29.  
  30.             $info[$field] = $value; 
  31.         } 
  32.     } 
  33.     return $info; 

代码整体比较容易,可能比较难理解的就是$this->fields这个参数,这个参数是初始化类member_input是插入的,这个参数分析起来比较繁琐,主要是对PHPCMS架构不熟,那就在此走点捷径吧,在1中,直接将初始化完成后的member_input类dump出来,效果还不错,所有的参数都dump到页面上了,下面主要摘取比较重要的$this->fields[$field],即:【$this->fields[“content”]】这个参数,如下所示⤵:

  1. ["content"]=> 
  2.     array(35) { 
  3.       ["fieldid"]=> 
  4.       string(2) "90" 
  5.       ["modelid"]=> 
  6.       string(2) "11" 
  7.       ["siteid"]=> 
  8.       string(1) "1" 
  9.       ["field"]=> 
  10.       string(7) "content" 
  11.       ["name"]=> 
  12.       string(6) "内容" 
  13.       ["tips"]=> 
  14.       string(407) "<div class="content_attr"><label><input name="add_introduce" type="checkbox"  value="1" checked>是否截取内容</label><input type="text" name="introcude_length" value="200" size="3">字符至内容摘要 
  15. <label><input type='checkbox' name='auto_thumb' value="1" checked>是否获取内容第</label><input type="text" name="auto_thumb_no" value="1" size="2" class="">张图片作为标题图片 
  16. </div>
  17.       ["css"]=> 
  18.       string(0) "" 
  19.       ["minlength"]=> 
  20.       string(1) "0" 
  21.       ["maxlength"]=> 
  22.       string(6) "999999" 
  23.       ["pattern"]=> 
  24.       string(0) "" 
  25.       ["errortips"]=> 
  26.       string(18) "内容不能为空" 
  27.       ["formtype"]=> 
  28.       string(6) "editor" 
  29.       ["setting"]=> 
  30.       string(199) "array ( 
  31.   'toolbar' => 'full', 
  32.   'defaultvalue' => '', 
  33.   'enablekeylink' => '1', 
  34.   'replacenum' => '2', 
  35.   'link_mode' => '0', 
  36.   'enablesaveimage' => '1', 
  37.   'height' => '', 
  38.   'disabled_page' => '0', 
  39. )" 
  40.       ["formattribute"]=> 
  41.       string(0) "" 
  42.       ["unsetgroupids"]=> 
  43.       string(0) "" 
  44.       ["unsetroleids"]=> 
  45.       string(0) "" 
  46.       ["iscore"]=> 
  47.       string(1) "0" 
  48.       ["issystem"]=> 
  49.       string(1) "0" 
  50.       ["isunique"]=> 
  51.       string(1) "0" 
  52.       ["isbase"]=> 
  53.       string(1) "1" 
  54.       ["issearch"]=> 
  55.       string(1) "0" 
  56.       ["isadd"]=> 
  57.       string(1) "1" 
  58.       ["isfulltext"]=> 
  59.       string(1) "1" 
  60.       ["isposition"]=> 
  61.       string(1) "0" 
  62.       ["listorder"]=> 
  63.       string(2) "13" 
  64.       ["disabled"]=> 
  65.       string(1) "0" 
  66.       ["isomnipotent"]=> 
  67.       string(1) "0" 
  68.       ["toolbar"]=> 
  69.       string(4) "full" 
  70.       ["defaultvalue"]=> 
  71.       string(0) "" 
  72.       ["enablekeylink"]=> 
  73.       string(1) "1" 
  74.       ["replacenum"]=> 
  75.       string(1) "2" 
  76.       ["link_mode"]=> 
  77.       string(1) "0" 
  78.       ["enablesaveimage"]=> 
  79.       string(1) "1" 
  80.       ["height"]=> 
  81.       string(0) "" 
  82.       ["disabled_page"]=> 
  83.       string(1) "0" 
  84.     } 

有了上面的参数列表后,理解get()函数的代码就要轻松许多了,分析过程略。结论就是,漏洞的触发函数在倒数6、7两行,单独截个图,如下⤵:

这里比较重要的是要找出$func这个函数,查查上面的表,找到[“formtype”]=>string(6) “editor”,可知$func就是editor()函数,editor函数传入的参数就是上面列出的一长串字符串,和img标签的内容,下面将跟进editor函数,真相好像马上就要大白于天下了。

3. 跟进editor函数及后续函数

editor()函数位于/phpcms/modules/member/fields/editor/imput.inc.php文件中,老规矩,先贴出代码:

  1. function editor($field, $value) { 
  2.         $setting = string2array($this->fields[$field]['setting']); 
  3.         $enablesaveimage = $setting['enablesaveimage']; 
  4.         if(isset($_POST['spider_img'])) $enablesaveimage = 0
  5.         if($enablesaveimage) { 
  6.             $site_setting = string2array($this->site_config['setting']); 
  7.             $watermark_enable = intval($site_setting['watermark_enable']); 
  8.             $value = $this->attachment->download('content', $value, $watermark_enable); 
  9.         } 
  10.         return $value; 
  11.     } 

简单阅读代码,发现实际的触发流程发生在$this->attachment->download()函数中,直接跟进这个函数,这个函数位于/phpcms/libs/classes/attachment.class.php中download()函数,源代码有点长,就贴一些关键代码,⤵

  1. $string = new_stripslashes($value); 
  2.     if(!preg_match_all("/(href|src)=([\"|']?)([^ \"'>]+\.($ext))\\2/i", $string, $matches)) return $value; 
  3.     $remotefileurls = array(); 
  4.     foreach($matches[3] as $matche) 
  5.     { 
  6.         if(strpos($matche, '://') === false) continue; 
  7.         dir_create($uploaddir); 
  8.         $remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref); 
  9.     } 
  10.     unset($matches, $string); 
  11.     $remotefileurls = array_unique($remotefileurls); 
  12.     $oldpath = $newpath = array(); 
  13.     foreach($remotefileurls as $k=>$file) { 
  14.                        if(strpos($file, '://') === false || strpos($file, $upload_url) !== false) continue; 
  15.         $filename = fileext($file); 
  16.         $file_name = basename($file); 
  17.         $filename = $this->getname($filename); 
  18.  
  19.         $newfile = $uploaddir.$filename; 
  20.         $upload_func = $this->upload_func; 
  21.         if($upload_func($file, $newfile)) { 

代码主要是进行一些正则过滤等等操作,这里真正关键的是代码的***一行的操作$upload_func($file, $newfile),其中$this->upload_func = ‘copy’;,写的在明白点就是copy($file, $newfile),漏洞就是一个copy操作造成的。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/121462.html<

(0)
运维的头像运维
上一篇2025-02-21 21:35
下一篇 2025-02-21 21:36

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注