simpleupload
这题苏师傅做出来了,但是我对着苏师傅简陋的wp没复现出来。桑心
1 |
|
我还是需要一张文件上传的思维图
题目分析
是thinkphp
框架,获取到上传的文件$_FILES['file']
之后,实例化一个类Upload()
,问题显然是出现在这个类上的
然而我最大的问题是,找不到上传的接口!!!
这就涉及到thinkphp的路由是怎么搞得,thinkphp
是单入口的框架,入口点在public/index.php
,之后是按照模块控制器方法来进行路由的。
但是这里的命名空间Home\Controller
,并不是以往熟悉的app\index\Controller
所以这里应该是一个单一模块的,也就是说上传接口在http://index.php/Home/index/upload
(这里就不是很明白了,明明这个Controller
是叫IndexController
这题虽然是限制了不能以.php
结尾,但是仔细查看才知道只是限制了$_FILES['file']
,这个file
只是在表单中设置的一个变量。
查看thinkphp
的源码可以看到。这个upload
方法直接就能上传所有的文件了
这样我们的利用思路就有了:
上传一个
file
的文件能够获得文件名,同时上传一个file1
的文件,这个文件也会被上传但是我们不知道它的文件名这时候爆破就好了
thinkphp3默认使用uniqid()函数根据时间生成文件名,两个文件上传时间相近可以爆破。
对这里还需要知道thinkphp
的版本
exp
1 | import requests |
总结
这题确实学到了很多东西,对于文件上传还不是很熟悉,那个$_FILES
数组,还有前后端是怎么交互的弄清楚了就好做了
文件上传类型简要分析
h4lo师傅写的文章感觉总结的很到位
分析文件上传时候的数据包
1 | Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA |
boundary
是一个字符串,用来切分数据。每个字段之间使用 ———WebKitFormBoundaryxxx 隔开
这里就和 post 请求一样,可以自己增加参数,就形如下面这样,将参数名放到 name 里,参数值放到下面:
1 | ------WebKitFormBoundary1PkqXeou9aUAIMHr |
那么这里就增加了一个参数 filename = ‘1.php’
前后端的交互就是通过这个name
进行的,也就是说后端会用$_FILES[filename]
这个数组,注意$_FILES
是一个二维数组,去获取这个文件的文件名,大小之类的信息。
这里有两个文件名,一个是上传的
name
,另一个是$_FIlES[filename]
简单地绕过
前端js这个不用说
也有通过MIME来校验的,
wafupload
简要分析一下这道题,前端可以通过表单上传文件,同时你可以自定义文件名(不过有啥用呢?)
因为后端会同时去判断你有没有自定义文件名
$file = empty($_POST['filename']) ? $_FILES['file']['name'] : $_POST['filename'];
白名单检测只能是'image/jpeg', 'image/png', 'image/gif'
,文件后缀也只能是'jpg', 'png', 'gif'
1 |
|
看似做的天衣无缝了,也确实考虑到了数组的情况:
1 | if (!in_array($ext, ['jpg', 'png', 'gif'])) { |
之后通古end
函数去取出文件的后缀名
但是end
函数有一个问题
end 函数取到的是给数组的最后一次赋值的那个值,继续尝试会发现 reset 函数也是一样,第一个给数组赋值的值就是 reset 函数返回的值
会根据赋值先后顺序该表值,可以去调试一下
这里的 end 函数取到了第二个给数组赋值的值,也就是 filename[0] ,reset 函数的值为 filename[1]。这边构造
1 | filename[1] = php |
在后面拼接 $filename 时候,再一次拼接到后缀名,即
1 | $filename = reset($file) . '.' . $file[count($file) - 1]; |
这里的
1 | $file[count($file) - 1] |
一定是取到 filename[1],所以上面给 filename[1] 赋值为 php 的意义就在这里。
上海网安赛 web3
1 |
|