对一次PHPCMS9.6任意文件上传的代码审计学习
字数 1539 2025-08-24 20:49:22
PHPCMS 9.6 任意文件上传漏洞分析与利用
漏洞概述
PHPCMS 9.6 存在一个任意文件上传漏洞,攻击者可以通过精心构造的注册请求,在服务器上上传任意PHP文件,导致远程代码执行(RCE)。该漏洞利用的是用户注册功能中对用户信息字段的处理不当。
漏洞环境
- 目标系统:PHPCMS 9.6
- 漏洞文件:
phpcms/modules/member/index.php - 相关文件:
caches/caches_model/caches_data/member_input.class.php
漏洞POC
siteid=1&modelid=11&username=test2&password=test2123&email=test2@163.com&info[content]=&dosubmit=1&protocol=
漏洞分析
正常注册流程
-
用户提交注册表单,包含以下关键参数:
siteid=1modelid=10(正常注册使用10,漏洞利用使用11)usernamepasswordemailinfo[birthday](正常注册使用生日字段)dosubmit=1
-
代码执行流程:
- 进入
phpcms/modules/member/index.php - 检查
dosubmit参数触发注册流程 - 处理
$_POST['info']参数 - 调用
member_input.class.php处理字段数据 - 对于
birthday字段,使用datetime函数处理 - 将用户信息插入
v9_member表 - 将详细信息插入
v9_member_detail表
- 进入
漏洞利用流程
-
攻击者构造特殊注册请求,关键变化:
modelid=11(使用不同的模型ID)info[content]替换info[birthday]content字段值为:``
-
异常处理流程:
- 进入
member_input.class.php处理content字段 - 匹配到
formtype为editor(编辑器类型) - 调用
editor函数处理$value - 对内容中的``进行下载处理
- 使用正则匹配URL:
http://127.0.0.1/phpinfo.txt?.php#.jpg - 截取
#之前的部分:http://127.0.0.1/phpinfo.txt?.php - 获取文件扩展名
.php - 将远程文件内容复制到本地,生成
.php文件
- 进入
-
漏洞触发点:
- 文件扩展名从URL参数
.php获取,而非实际文件名.txt #.jpg用于绕过初步检查,但实际不影响最终文件扩展名- 最终生成可执行的PHP文件
- 文件扩展名从URL参数
-
路径泄露原因:
- 恶意内容尝试插入数据库时与表结构不匹配
- 导致SQL错误并返回完整路径信息
漏洞复现步骤
- 搭建PHPCMS 9.6环境
- 准备一个可访问的文本文件(如phpinfo.txt)包含PHP代码
- 构造恶意注册请求:
POST /index.php?m=member&c=index&a=register HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded siteid=1&modelid=11&username=test2&password=test2123&email=test2@163.com&info[content]=&dosubmit=1&protocol= - 观察响应,获取生成的文件路径
- 访问生成的PHP文件执行任意代码
防御措施
-
输入验证:
- 严格验证用户提交的所有字段
- 对
info数组中的内容进行过滤
-
文件处理:
- 下载远程文件时应验证实际文件类型
- 禁止从URL参数获取文件扩展名
- 限制可上传的文件类型
-
错误处理:
- 关闭错误信息显示
- 使用自定义错误页面
-
代码修复:
- 更新到最新版本
- 修改
editor函数中的文件处理逻辑
学习要点
-
代码审计方法:
- 先理解正常功能流程
- 再分析异常输入处理
- 关注数据流变化
-
漏洞挖掘思路:
- 关注用户输入点
- 跟踪数据处理流程
- 寻找非常规的参数组合
-
开发安全建议:
- 避免从用户可控输入中获取关键参数
- 实现严格的白名单验证
- 对文件操作进行多重验证
总结
该漏洞展示了如何通过精心构造的输入利用系统功能实现任意文件上传,强调了输入验证和文件处理安全的重要性。通过分析这类漏洞,安全研究人员可以更好地理解Web应用程序的安全风险,并采取适当的防护措施。