文件上传
文件上传漏洞是由于对上传文件的内、类型没有做严格的过滤、检查,使得攻击者可以通过上传木马文件获取服务器的webshell文件
low
上传一个php文件,上传成功,并且可以在WWWDVWAhackableuploads目录下找到该文件
此难度没有做任何过滤,所有文件都可以上传
源码审计
没有做任何过滤,很危险的行为
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 检查表单是否提交了"Upload"按钮 // 定义目标上传路径 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; // 设置目标路径为一个固定目录 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // 将上传文件的基础名称附加到目标路径 // 尝试将文件移动到上传文件夹 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // 如果移动失败 // 上传失败,显示错误信息 $html .= '<pre>Your image was not uploaded.</pre>'; // 提示用户图像未上传 } else { // 如果成功 // 上传成功 $html .= "<pre>{$target_path} successfully uploaded!</pre>"; // 提示用户图像成功上传,并显示路径 } } ?>
medium
先上传一个php文件
只允许上传jpg/png图片,那么就上传这两种图片
上传成功
源码审计
只允许上传文件类型jpg/png内容,以及文件大小小于10000字节,过滤并不严谨
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 检查表单是否提交了"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' ]; // 获取上传文件的大小 // 检查是否为图像文件 if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && // 如果是JPEG或PNG格式 ( $uploaded_size < 100000 ) ) { // 并且文件大小小于100000字节(约100KB) // 尝试将文件移动到上传文件夹 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // 如果移动失败 // 上传失败,显示错误信息 $html .= '<pre>Your image was not uploaded.</pre>'; // 提示用户图像未上传 } else { // 如果成功 // 上传成功 $html .= "<pre>{$target_path} successfully uploaded!</pre>"; // 提示用户图像成功上传,并显示路径 } } else { // 如果文件不符合条件 // 提示无效文件 $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; // 提示用户只接受JPEG或PNG格式的图像 } } ?>
high
根据提示只允许上传图片文件,上传一个jpg图片结果上传失败
上传并抓包,发送到重放器
添加文件头即可,GIF89a
源码审计
限制了文件后缀及文件内容是否有效,对文件类型过滤不严谨,如果添加文件头,则会被解析为一个jpg文件,就可以正常上传
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 检查是否有提交的"Upload"表单 // 定义目标写入路径 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; // 设置目标路径为指定文件夹 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // 将上传文件的基础名称附加到目标路径 // 文件信息 $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' ]; // 获取上传文件的临时存储路径 // 检查文件是否为图像 if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && // 如果扩展名是jpg、jpeg或png(不区分大小写) ( $uploaded_size < 100000 ) && // 并且文件大小小于100000字节(约100KB) getimagesize( $uploaded_tmp ) ) { // 并且临时文件是有效图像 // 尝试将文件移动到上传文件夹 if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { // 如果移动失败 // 上传失败,显示错误信息 $html .= '<pre>Your image was not uploaded.</pre>'; // 提示用户图像未上传 } else { // 如果成功 // 上传成功 $html .= "<pre>{$target_path} successfully uploaded!</pre>"; // 提示用户图像成功上传,并显示文件路径 } } else { // 如果文件不符合条件 // 提示无效文件 $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; // 提示用户只接受JPEG或PNG格式的图像 } } ?>
impossible
源码审计
非常严格的过滤,对上传的文件进行了重命名(搞了一个MD5的加密),还增加了token值的校验,对文件的内容也做了严格的检查。
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 检查是否提交了"Upload"表单 // 检查反CSRF令牌 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 ) . '-'; // 原来可以使用的文件名 $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; // 生成临时文件的完整路径 // 检查文件是否为图像 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 ) ) { // 检查文件是否为有效图像 // 去除任何元数据,通过重新编码图像(推荐使用php-Imagick替代php-GD) if( $uploaded_type == 'image/jpeg' ) { // 如果文件类型为JPEG $img = imagecreatefromjpeg( $uploaded_tmp ); // 创建JPEG图像 imagejpeg( $img, $temp_file, 100); // 以最高质量重新编码并保存到临时文件 } else { // 如果文件类型为PNG $img = imagecreatefrompng( $uploaded_tmp ); // 创建PNG图像 imagepng( $img, $temp_file, 9); // 以最高压缩率重新编码并保存到临时文件 } imagedestroy( $img ); // 销毁图像资源以释放内存 // 尝试将文件从临时文件夹移动到目标路径 if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { // 如果移动成功 // 上传成功 $html .= "<pre><a href='{$target_path}{$target_file}'>{$target_file}</a> successfully uploaded!</pre>"; // 显示上传成功的消息,并提供文件链接 } else { // 如果移动失败 // 上传失败 $html .= '<pre>Your image was not uploaded.</pre>'; // 提示用户图像未上传 } // 删除任何临时文件 if( file_exists( $temp_file ) ) // 如果临时文件存在 unlink( $temp_file ); // 删除临时文件 } else { // 如果文件不符合条件 // 提示无效文件 $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; // 提示用户只接受JPEG或PNG格式的图像 } } // 生成反CSRF令牌 generateSessionToken(); ?>