【DVWA】File Upload

【DVWA】File Upload

一、low级别

1、测试流程

上传一张图片:

image-20210301143751573

如图所示,上传成功!

上传冰蝎木马:

image-20210301145206316

如图所示,上传成功!

image-20210301145610375

成功getshell.

2、源码分析

 <?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' ] ); //在上传的目录下加上uploaded传来的文件名

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

?>

从上面的源码可以看出,文件在上传时并没有对文件的类型、大小、内容等做过滤和限制,存在明显的文件上传漏洞。

二、Medium级别

1、测试流程

  • 上传一张图片

image-20210301150537408

上传成功!

尝试上传冰蝎的大马shell.php

image-20210301151857669

上传失败

  • 尝试更改数据包content-type字段内容

    image-20210301152705220

    image-20210301152719828

    上传成功!

    然后用冰蝎链接即可getshell.

2、源码分析

<?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' ];  //获取上传文件的name
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];  //获取上传文件的类型,通过MIME判断
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];  //获取上传文件的大小

    // Is it an image?
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {
    //采用白名单过滤的方式,只接受.jpeg,.png的图片文件,并且文件大小设置在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获取的,所以用burp抓包后直接更改文件类型(content-type字段)即可绕过。

三、high级别

1、测试流程

上传一张图片

image-20210301154146764

上传成功!

更改数据包的content-type字段,仍然上传失败。

于是制作图片木马:

image-20210301160904224

image-20210301161529142

image-20210301161921365

尝试上传:

image-20210301161944448

上传成功!

但由于文件是图片格式,无法直接执行,需要借助其他漏洞。

漏洞利用思路:

1、利用命令注入漏洞将muma.png的后缀改为php,再用菜刀连接

2、利用文件包含漏洞包含muma.png,再用菜刀连接。

image-20210301162442801

2、源码分析

<?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()函数:函数查找字符串在另一字符串中最后一次出现的位置。

substr() 函数:返回字符串的一部分。substr(string,start,length) length为可选

strtolower() 函数:把字符串转换为小写。

getimagesize() 函数:用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。

由此可知,后端代码对上传的文件后缀进行白名单过滤,用getimagesize()函数二进制检测图片头部信息,然后对文件大小也进行了限制。绕过方法:制作图片木马,借助其他漏洞getshell

四、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();   //预防CSRF攻击

?> 

uniqid() 函数:基于以微秒计的当前时间,生成一个唯一的 ID。

ini_get(varname)函数:获取一个配置选项的值,成功是返回配置选项值的字符串,null 的值则返回空字符串。如果配置选项不存在,将会返回 false。注: upload_tmp_dir 的这个参数为上传文件的临时目录。

sys_get_temp_dir()函数:返回默认情况下PHP将临时文件存储在其中的目录的路径。

imagecreatefromjpeg(filename)函数: 返回一图像标识符,代表了从给定的文件名取得的图像。

jmagejpeg(image, filename, quality)函数:从image图像以filename为文件名创建一个JPEG图像,可选参数quality,范围从 0(最差质量,文件更小)到 100(最佳质量,文件最大)。

imagedestroy(resource $image)函数:在图像的所有资源使用完毕后,通常需要释放图像处理所占用的内存。在 PHP 中可以通过 imagedestroy() 函数来释放图像资源,$image 为要释放的图像资源。

rename(oldname,newname,context)函数:重命名文件或目录。context可选,规定文件句柄的环境。

getcwd()函数:获取当前工作目录。

file_exists(文件指定路径) 函数:检查文件或目录是否存在,如果指定的文件或目录存在则返回 true,否则返回 false。

unlink(文件指定路径) 函数:删除文件。若成功,则返回 true,失败则返回 false。

可以看到,Impossible级别的代码对上传文件进行了重命名(为md5值,导致%00截断无法绕过过滤规则),加入Anti-CSRF token防护CSRF攻击,同时上传成功后作不显示文件上传的路径,导致攻击者无法连接上含有恶意脚本的图片文件。而且似乎将图片重做了,在上传的图片文件中也找不到恶意脚本了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>