yccms代码审计(php)
yccms代码审计(php)
搭建环境
- 更改config.inc.php对应的数据库名,用户名及密码即可
- 运行yccms.sql文件,在数据库中导入sql数据
- 访问http://域名/admin,用户名及密码都为admin,登录后台
配置xdebug
参考文章:
2024年更新,PhpStorm配置Xdebug最完整最详解教程,100%成功! - 个人文章 - SegmentFault 思否
小迪安全php代码审计课程 day108
详细步骤:
phpstorm左上角file(菜单)->setting(设置)->php->sever
新建一个服务器,名称任意,端口与网站搭建端口一致

phpstorm左上角file(菜单)->setting(设置)->php->Debug(调试)
设置端口号为9100,防止端口进程冲突

调试下的DBGp按照如图设置,端口与刚刚设置的调试端口相对应

打开phpstudy,查看网站使用的php版本
在软件管理选项中找到对应的php版本,点击设置
打开xdebug调试组件,端口监听与刚刚设置的调试端口设为一致

phpstorm左上角file(菜单)->setting(设置)->php
将版本设置为与刚刚在phpstudy中查看的此网站使用的php版本

右上角添加配置中选择php网页添加配置

审计
目录结构

可以看出此源码是MVC结构,最核心的控制代码在controller与model文件夹内
翻看目录发现此源码使用了smarty模板,随后可以查看是否存在ssti模板注入
路由关系
?a=admin&m=update
key值为a传入类名,key值为m传入方法名
漏洞复现(有入口,才可利用)
参考:记一次完整的PHP代码审计——yccms v3.4审计 - KRookieSec - 博客园 (cnblogs.com)
代码审计—YCCMS系统-先知社区 (aliyun.com)
使用seay进行自动化审计,找到可能存在漏洞的地方,逐个测试

代码执行
找到此方法是否有被实例化
发现run.inc.php实例化此方法,admin/index.php包含了此文件
public/class目录下的Factory.class.php文件,文件类名为Factory
1 | |
eval函数内变量可控
需要传入一个类名,并且满足(或绕过)file_exists()函数的检查
构造payload
1 | |
分析:
- 调用Factory()类中方法
- 用;隔开以执行下一条语句
- /../跳至上一级绕过file_exist()函数检测
顺利注入

尝试写入一句话木马
1 | |
看一些文章是可以顺利连接的,我这里没有成功
无需登录文件删除
controller/PicAction.class.php文件中控制删除功能的方法没有对文件名及文件路径的检测
1 | |
其他文件有文件路径检测,如:
1 | |
开始测试
寻找网站功能点:其他功能->图片管理
点击删除按钮后抓取数据包,得到数据包内容

send值是url编码过的,解码后为删除选中图片
pid后url编码解码后为[0]
退出admin账户的登陆后,将网站根目录下CMS系统安装声明文件重命名为CMS(一会测试时无需再对中文url编码)
更改数据包pid[0]参数的值为/../CMS,发送数据包,发现成功删除文件
无需登录文章删除
controller/ArticleAction.class.php
漏洞代码
1 | |
通过代码可以看到基本上是没有检测的,传入id即可删除对应的文章,但是由于变量是固定的,所以只能删除文章
不能删除其他文件
开始测试:
寻找功能点:内容管理->文章列表
点击删除抓取数据包

看到是直接get传参,更改id的值就可以的
退出登录后更改id发送数据包,再次登录查看,发现顺利删除文章
无需登录文件上传01
public/class/FileUpload.class.php
查看源代码发现只对上传图片类型和文件大小做了判断,并且进行了重命名
在网站寻找功能点:系统设置->首页内容
在编辑器自带的文件上传功能点处可以上传文件
抓取数据包,更改文件名和文件内容,顺利上传

用蚁剑成功连接

经测试,退出登陆后直接发包也可以正常上传,可以正常连接
无需登录文件上传02
直接寻找功能点:系统设置->上传logo
找到对应控制代码

上传后的文件会被重命名为logo,检验文件类型的函数极容易绕过
方法同01抓取数据包后更改文件内容与文件名
可以看到顺利上传

用蚁剑测试依旧是能够连接成功

退出登录后同样可以发送数据包并且用蚁剑顺利连接
任意密码修改(未鉴权)
controller/AdminAction.class.php
1 | |
可以看到登录到后台页面是有鉴权的,但是执行update方法时就没有鉴权了
在网站找到功能点:其他功能->修改密码
抓取数据包,在数据包中做数据的修改

网站退出登录后可以正常发送数据包
尝试新用户名和密码后发现可以正常登录
rce(Action.class.php)误报
路径:controller/Action.class.php
调用eval函数,可能存在rce漏洞
1 | |
查找利用点时发现每一个controller中的文件都继承了此类
构造payload(http://localhost/yccms/admin/?a=admin&m=phpinfo)发现并没有回显
使用动态调试后可以看到m的值初始时为phpinfo

经过run.inc.php方法中代码Factory::setAction()->run();
1 | |
m的值被替换为main
查看setAction方法,此方法中的可控变量是a
1 | |
此代码大致作用:
- 获取请求参数
a来确定控制器; - 若请求的是后台控制器,且用户未登录,则重定向到登录页面;
- 若控制器类文件不存在,则默认使用
LoginAction; - 创建控制器类的对象,并返回
所以无法调用传入的控制器内不存在的方法
存在eval函数的方法是run方法,像另一个成功执行的rce漏洞一样构造payload
1 | |
仍然无法注入成功
可以看到在步入run.inc.php后,m的值变为main
文件包含(run.inc.php)误报
工具审计时发现了require关键字,可能存在文件包含漏洞
但是require函数内无可控变量,无法利用此函数
总结
自动化工具一般是直接搜索关键字或敏感函数,误报很多
找漏洞关键要看漏洞点和利用点,有入口能利用才算漏洞
寻找敏感函数和可控变量,查看变量有无过滤,过滤是否可绕过
cms漏洞:
- 鉴权处理不到位,大部分操作都没有鉴权,无需登录就可操作
修复建议:写出单独的鉴权文件,在每个类中引用
- 过滤不严格,对文件名及文件路径几乎无过滤