DVWA学习(七)文件上传漏洞

引言

DVWA学习(七)文件上传漏洞

简介

File Upload,即文件上传漏洞,通常是由于对上传文件的类型、内容没有进行严格的过滤、检查,使得攻击者可以通过上传木马获取服务器的webshell权限,因此文件上传漏洞带来的危害常常是毁灭性的。简单点说,就是用户直接或者通过各种绕过方式将webshell上传到服务器中进而执行利用。

保存一句话木马为muma.php

LOW级别

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>

basename() 函数返回路径中的文件名部分。
move_uploaded_file() 函数将上传的文件移动到新位置。
若成功,则返回 true,否则返回 false。
file 必需。规定要移动的文件。
newloc 必需。规定文件的新位置。

1
2
3
4
5
$_FILES["file"]["tmp_name"] - 存储在服务器的文件的临时副本的名称
$_FILES["file"]["name"] - 被上传文件的名称
DVWA_WEB_PAGE_TO_ROOT是网站根目录
没有任何过滤,可以上传任意文件。
上传muma.php显示了文件路径../../hackable/uploads/muma.php succesfully uploaded!用中国菜刀

然后菜刀就会通过向服务器发送包含haha参数的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
24
25
26
27
28
29
30
31
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>

这里采用白名单过滤只允许上传文件的 MIME类型为image/jpeg或者image/png以及文件大小小于100000字节。

1.用burp更改content-type就行

2.截断绕过规则

在php版本小于5.3.4的服务器中,当Magic_quote_gpc选项为off时,可以在文件名中使用%00截断,所以可以把上传文件命名为muma.php%00.png

而服务器会认为其文件名为hack.php,顺势解析为php文件。(仅限于php版本小于5.3.4的版本)

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
25
26
27
28
29
30
31
32
33
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];

// Is it an image?
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {

// Can we move the file to the upload folder?
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>

substr(string,start,length)返回字符串的一部分。
strrpos()查找第二个参数在第一个参数中最后一次出现的位置
$uploaded_ext等于文件的后缀名
getimagesize(string filename)函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。

仍然采用白名单过滤,只允许上传的文件后缀名为jpg,jpeg,png以及文件大小小于100000字节。getimagesize函数限制了上传文件的文件头必须为图像类型。

1.采用%00截断

需要将上传文件的文件头伪装成图片。常见的图片格式的文件头标识如下:

用copy将一句话木马文件php.php与图片文件1.jpg合并

记事本打开可以发现一句话木马藏在了图片里

绕过后缀检查

然后需要用到文件包含漏洞。

1
http://192.168.86.128/DVWAmaster/vulnerabilities/fi/?page=file:///var/www/html/DVWA-master/hackable/uploads/muma.jpg

在文件包含漏洞页面成功加载图片

然后用菜刀,地址栏填上面的url,参数名 haha,

连接失败,cookie里会有两个相同的参数,导致访问失败。wirteup上说是DVWA的BUG

%00 截断需要 PHP<5.3.4,实验环境为 5.6.35 所以无法利用。

impossible难度

源码

1
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];

// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;

// Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {

// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );

// Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
}

// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>

uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。由于基于系统时间,通过该函数生成的 ID 不是最佳的。如需生成绝对唯一的 ID,需使用 md5() 函数。

ini_get — 获取一个配置选项的值。
upload_tmp_dir上传文件的临时目录。
sys_get_temp_dir — 返回用于临时文件的目录。
DIRECTORY_SEPARATOR是一个返回跟操作系统相关的路径分隔符内置命令,在windows上返回\,而在linux或者类unix上回/。
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像。
( imagecreatefrom,会检查图片规范,验证图片合法性,以此抵御图片中含有恶意 php 代码的攻击。)
php imagecreatefrom
系列函数之 png – janes。
imagejpeg(a,b,c) 从 image 图像以 b为文件名创建一个JPEG 图像,c为文件质量1-100,默认约为75。
PHP getcwd() 函数获取当前工作目录。
file_exists() 函数检查文件或目录是否存在。
unlink() 函数删除文件。
impossible级别的代码对上传文件进行了重命名(为md5值,导致%00截断无法绕过过滤规则),加入Anti-CSRF token防护CSRF攻击,同时对文件的内容作了严格的检查,导致攻击者无法上传含有恶意脚本的文件。

介绍:仅供技术交流学习探讨,请勿用于非法用途。本文部分资源来源于网络,如有侵权请联系版主删除。

-------------本文结束感谢您的阅读-------------
纯属好玩,打赏多少您随意!