初识php代审——baijiacms
百家CMS代码审计
1、环境准备
phpstudy8.1.1.3
apache2.4.39+mysql5.7.26+php5.3.29
2、搭建环境
先搭建一个百家数据库,为搭建站点做准备。
直接使用phpstudy搭建好站点,并访问
连接数据库,并配置系统管理员
然后就成功创建了
3、路由审计
路由关系是代码审计第一步,我们可以通过找到代码、目录与网站页面的对应关系,让我们更好的验证漏洞
先走一下基础流程,大概的看一下目录结构,有个大概的印象
大概目录解释
1 |
|
开始找路由关系,一些根基比较深的cms,往往有自己独家的路由设置,有使用手册的话,还需要通过cms的使用手册上去梳理路由关系。但是有个小捷径,就是可以直接对比站点的url和源码的目录结构,这个方法很快,更便于理解。
我们点进修改密码功能点,然后看看url
根据url中的关键字来找代码文件,直接全局检索”changepwd”,锁定到了三个文件
然后再根据url中的”manage”关键字,多半就是第一个
1 |
|
所以url中的act就对应system目录下下的目录,do就是对于的文件,但是mod是什么,我们再看一下baijiacms\system\manager\template\web\changepwd.php,这个路径,都不存在mod传递的键值”site”,于是我直接修改一下mod参数的参数值为web,同时删除了beid参数
结果还是正常访问,说明这里mod参数其实是文件的上一级目录,可能是开发的小心思,使用site可以平替web,现在我们就摸清路由关系了,如下
mod(目标文件上一级目录)、act(system下一级目录)、do(目标文件名)
4、漏洞审计
审计前言
一般的审计思路,分以下几种(经验浅显,还望大哥们斧正):
1、直接通过可控变量查看漏洞点,但是不推荐,因为cms中变量太多,单纯通过POST、GET传参的变量数不胜数,量大且效率低下。
2、直接通过危险函数审计,全局检索危险函数,再查看危险函数的相关参数是否可控,如果可控再次跟进是否可以利用,更有目的性,但还是比价耗时间。
3、结合黑盒的思路,也即是跟根据功能点查找,这个可以快速的找到入手点,但是检索不全面,会审计不全面。
4、直接分析目录的结构同时结合网站页面,搞明白每个目录、文件、参数传递的对于的网站功能,也就是差不多通读源码了,这个虽然很费时间,但是可以让审计更加得心应手,也比较能审一些深入的洞
迫于刚刚接触白盒审计,只能站在各位大佬的肩膀上,复现大佬们的漏洞点了。
漏洞1:任意目录及文件删除
通过全局检索关键删除文件函数unlink(),找到如下漏洞点
继续跟进,发现了一个file_delete函数
该函数的大概流程是
1、empty函数判断文件是否为空,如果为空就返回true
2、$settings[‘system_isnetattach’],这是一个系统设置(此处就是是否开始了oss、ftp存储文件,为1则是开启了),empty($settings[‘system_isnetattach’]),判断系统设置为空则返回true,加上!,则是设置为空时,就跳过以下的代码(用来删除oss、ftp中存储的文件)
3、此时直接跳转到,判断如下:判断是否文件存在,则可以触发删除函数unlink(),同时发现没有对$file_relative_path,做任何过滤。
1 |
|
通过全局检索file_delete(
,跳转到使用该函数的代码块
定位到uploadeuploader.php
查看其代码逻辑
根据文件名和初步判断,这个文件大概分为两个部分,当$operation为upload时,进行文件上传操作;为remove时就会调用file_delete()函数,但是文件名变量使用$_GPC[‘file’],这种形式怪怪的,没有见过,我们该怎么传参呢?
这个其实是该CMS特殊的定义,我们就看看其定义:
没错,这个是global定义的变量,这使得php函数内部可以访问函数外部的全局变量,肯定也不乏超全局变量,所以索性我们就直接使用GET传参就行了。
除此之外还需要满足条件
1 |
|
而该operation变量,也通过使用global定义
我们也就可以再次使用GET传参
漏洞1验证
为了验证漏洞我们在根目录baijiacms下创建一个test.txt文件
然后根据文件判断漏洞路由,构造URL来验证即可,uploader.php文件的路径为
1 |
|
根据我们之前的路由判断
1 |
|
应该就可以实现任意文件删除了
失败了?不,难道是test.txt的路径不对?我们网站的各个页面是基于system目录下的,而我们的test.txt文件和system目录同属baijiacms根目录下的,我们加个相对路径试一试,不过我们还是最好加一个回显,判断漏洞验证成功
使用以下payload再试一试
1 |
|
还是回显为空!
哪一步出了问题?经过再次在网站上点点点,发现还有一种路由方式,我勒个豆!
出现了多余的m参数,于是我们再翻一翻目录结构
根据url找到了,上述目录及其文件,再根据php文件中,含有评论
关键词与web界面的评论管理
的匹配度,大概确定,就是这个路径了。根据上述再次梳理路由,url参数
mod(目标文件上两级目录)、act(目标文件名)、do(目标文件上一级目录)、m(system下的目录)
于是我们再次构造payload
1 |
|
成功删除文件
真的如此吗?
真的难缠,还是没有成功删除,为什么?因为根据上面的函数执行逻辑可知,这个函数确实执行了,但是开发疏忽了,无论目标文件是否存在都会这样回(此时可以在原函数再加个回显,但是我们不是开发,就不必在乎了),我们再使用../
相对路径,看能否删除
再看,嗯嗯对啦,删除了
漏洞2:命令执行
针对命令执行,我们关注的函数肯定是eval
、system
、exec
这几个,所以接下来就尝试去利用全局搜索来寻找可疑点。
通过检索system函数,找到如下结果
其函数在一个file_save函数中,找到可控变量file_full_path(文件完整路径),就看一看如何触发system函数
主要是让(!empty($settings['image_compress_openscale']))
判断为true,同时根据上面setting的由来”globaSystemSetting()”,其实setting变量就是存储系统设置的一个数据,这个设置需要我们从web界面中去勾选,所以现在就是要定位这个设置的页面在哪
我们直接全局检索”image_compress_openscale”
锁定文件netattach.php文件,应该就是设置页面,根据构造路由直接去访问
其路径为baijiacms\system\manager\template\web\netattach.php
构建url:
1 |
|
然后如下开启即可
好,现在我们就可以从file_save中接触到system方法了,现在需要file_save被调用的情况。全局检索,发现在setting.php中
看一下代码逻辑
要先使checksubmit()函数返回为true,然后才能触碰到下一个判断”$extention==’txt’”,才会执行到file_save函数,所以我们跟踪checksubmit(),如下
我们只需要保证不进入第一个if(if (!empty($action)&&empty($_GP[$action]))
),然后后面随便满足一个即可,第一个判断的逻辑:
如果传入的 $action
非空,并且 $_GP[$action]
(即请求中的某个参数)为空,返回 FALSE
。即检查相关操作是否存在,若不存在则返回 FALSE
。
第二个判断是否为get请求,该函数默认变量$allowget为false,肯定就不会让其判断为真
第三个判断是否为Ajax请求,并且用global定义的变量来判断,我们可以直接GET传参真
即可
现在到下一个突破口$extention=='txt'
先看extention变量来源于一个文件,应该是页面有个文件上传功能点,extention变量经历了pathinfo函数,该函数就是一个取得文件后缀名的一个函数,然后对后缀名进行小写,判断后缀名是不是txt,所以我们只需要上传一个txt文件就可以判断为真。
从而调用到file_save函数
1 |
|
其中的WEB_ROOT.”/“.$file[‘name’],对应之前的可控变量$file_full_path,所以我们只需要把文件名当作命令,并进行适当闭合,就可以实现命令执行了,开始实践
漏洞2验证
查看漏洞文件路径
1 |
|
构造url:
1 |
|
的确有一个上传接口
并构建一个闭合的命令执行的文件:&ipconfig&.txt,如下构造
然后直接提交,成功命令执行
不过要插一句这里文件上传,并提交的过程中,应该就是使用的ajax发送的请求,也就不需要再使用GET传入参数isajax=1
了
漏洞3:任意文件上传
直接定位文件上传函数:move_uploaded_file
但是它是在ExcelModel类中,并且这个类并没有被实例化,就没有深究下去,于是检索了一下关键字upload(
白名单,而且过滤写得很死,几乎没什么机会
继续寻找,寻到了fetch_net_file_upload函数方法
逻辑如下:使用pathinfo函数,获取了一个文件后缀名,创建文件夹,以<文件名/年/月>的形式,然后生成随机的文件名,构建文件路径,根据url下载文件,并保存文件。没有什么过滤。
查看fetch_net_file_upload函数调用关系
查看file.php
要执行fetch_net_file_upload,要先$do == ‘fetch’(GET传参op=fetch
),然后传参url即可实现任意文件上传
漏洞3验证
老规律定位路由
1 |
|
构造payload
1 |
|
访问,成功getshell!
本地以为就这么getshell,结果回头一瞧。哥们就这么水灵灵被当作前端代码,给露出来了
只能得到一个存储xss
修改phpinfo.php文件中的内容
总结
初识审计,学到了很多!如何比较快速地寻找路由,审计的大概思路和顺序,对之后的审计也越来越自信了,不过还是很缺乏独自挖掘漏洞的能力,所以还是要多看看大佬们的审计文章,努力赶上佬们!!!