DVWA靶场通过——文件上传漏洞

发布于:2024-11-29 ⋅ 阅读:(28) ⋅ 点赞:(0)

File Upload漏洞

它允许攻击者通过上传恶意文件来执行任意代码、窃取数据、获取服务器权限,甚至完全控制服务器。为了防止文件上传漏洞,开发者需要对文件上传过程进行严格的验证和处理。

1. 文件上传漏洞概述

文件上传漏洞发生在Web应用程序允许用户通过表单上传文件时,如果文件上传机制没有进行严格的验证和限制,攻击者可以上传恶意文件。这些恶意文件通常包含恶意脚本(如PHP、ASP、JSP等)或二进制代码,可能被执行,造成远程代码执行(RCE)等严重安全问题。

2. 文件上传漏洞的常见利用方式

A. 执行恶意脚本(Remote Code Execution,RCE)

攻击者可以上传一个包含恶意PHP脚本的文件,利用文件上传漏洞执行任意PHP代码。这些文件通常

以 .php、.php3、.php4 等文件扩展名上传。

攻击方式:

  1. 上传恶意文件:攻击者上传一个恶意的 .php 文件,例如 shell.php,该文件包含恶意PHP代码。
  2. 访问文件:攻击者通过浏览器访问该文件,并触发其中的PHP代码,从而执行任意命令或代码。

例如,上传一个包含以下内容的 PHP 文件:

<?php
system($_GET['cmd']);
?>

攻击者可以通过访问该文件并提供 cmd 参数来执行任意系统命令:

http://victim.com/uploads/shell.php?cmd=ls

B. 路径遍历攻击(Directory Traversal)

攻击者通过路径遍历技术(../)操纵文件路径,将上传的文件保存到服务器上的其他目录,进而绕过文件上传限制。路径遍历通常出现在文件上传过程中,没有对上传路径进行有效的校验和限制。

例如,攻击者可以通过上传带有路径遍历的文件名:

../../../../../etc/passwd

如果服务器没有适当的安全检查,攻击者能够上传并访问 /etc/passwd 文件,进而获取敏感信息。

C. 替换现有文件

攻击者可以通过上传文件覆盖已有的关键系统文件或Web应用程序文件。例如,如果应用程序未对文件名进行充分验证,攻击者可以上传一个与现有文件同名的恶意文件并覆盖它。

D. 社交工程攻击

攻击者通过上传看似无害的文件(如 .jpg、.png、.pdf 等)进行社交工程攻击,诱使管理员或其他用户打开这些文件。虽然这些文件本身不包含恶意代码,但它们可能被用来作为后续攻击的载体,或者是作为伪装用来隐藏恶意文件的手段。

E. 服务器端请求伪造(SSRF)

通过上传某些特定类型的文件(如图片、PDF文件)并且恶意地构造内容,攻击者可能利用Web应用程序执行未经授权的内部请求,甚至访问服务器上的其他内部资源。

3. 防范File Upload漏洞的最佳实践

防范文件上传漏洞需要从多个角度进行防护。下面列出了一些防范上传漏洞的最佳实践:

A. 文件类型验证

确保上传的文件类型是预期的类型。仅允许上传特定扩展名的文件(如 .jpg, .png, .pdf 等)。

  • 文件扩展名:对文件的扩展名进行严格检查,防止上传恶意脚本文件(如 .php, .jsp)。
  • MIME类型验证:不仅验证文件的扩展名,还应检查文件的 MIME 类型。例如,确保上传的图片文件具有 image/jpeg 或 image/png 类型,而不是 application/x-php 等恶意类型。

$allowed_types = ['image/jpeg', 'image/png'];
$file_type = mime_content_type($_FILES['file']['tmp_name']);
if (!in_array($file_type, $allowed_types)) {
    echo "Invalid file type!";
    exit;
}

B. 文件名验证

对上传的文件名进行严格的验证,防止路径穿越(../)攻击,确保文件保存路径是安全的。

  • 使用 basename() 函数来获取文件的基本名称,并移除任何路径部分:

$file_name = basename($_FILES['file']['name']);

  • 防止文件名中出现恶意字符(如 ..、/ 等)。

C. 限制文件大小

通过设置最大文件上传大小限制,防止上传超大文件造成的资源耗尽攻击(DoS攻击)或系统崩溃。

在PHP中可以通过配置 upload_max_filesize 和 post_max_size 来控制上传文件的最大大小:

upload_max_filesize = 5M
post_max_size = 8M

D. 限制上传的文件数量

限制每个用户或每个会话可以上传的文件数量,避免大量恶意文件上传。

E. 使用临时存储

将上传的文件首先存储在临时目录中,不直接放到 Web 可访问的目录。然后,服务器可以在对文件进行验证后,才将其移动到正式目录。

$tmp_file = $_FILES['file']['tmp_name'];
$upload_dir = '/var/www/uploads/';
$final_file = $upload_dir . basename($_FILES['file']['name']);
if (move_uploaded_file($tmp_file, $final_file)) {
    echo "File uploaded successfully.";
} else {
    echo "File upload failed.";
}

F. 文件内容扫描

上传的文件可以通过 文件内容扫描 进行进一步验证,尤其是对可执行文件(如 PHP 文件、脚本文件)进行检查。例如,检查文件是否包含恶意代码、脚本标签或 PHP 标签。

  • 对上传的 PHP 文件进行 eval() 等关键字的扫描,阻止可执行脚本的上传。

G. 限制文件扩展名

通过严格的规则来控制上传的文件类型,允许的扩展名可以是特定的静态文件类型(如 .jpg、.png、.txt 等),而拒绝其他动态文件类型(如 .php、.asp、.jsp 等)。

$allowed_extensions = ['jpg', 'png', 'jpeg', 'gif'];
$extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
if (!in_array(strtolower($extension), $allowed_extensions)) {
    echo "Invalid file extension!";
    exit;
}

H. 禁止执行上传文件

即使上传了有效的文件,也要确保文件不会被执行。可以通过设置正确的文件权限或禁用Web目录中的文件执行。

  • 设置上传目录的权限,确保其中的文件无法被执行:

chmod 755 /var/www/uploads

  • 配置Web服务器(如 Apache 或 Nginx)禁用上传目录下的 PHP 文件执行。
    • 在 Apache 中可以使用 Options -ExecCGI 来禁止文件执行。
    • 在 Nginx 中可以使用 location 配置来阻止 PHP 文件的执行:
      location ~* \.php$ {
          deny all;
      }

I. 使用Web应用防火墙(WAF)

部署Web应用防火墙(WAF)来防御上传恶意文件的攻击。WAF可以通过实时监控、过滤文件内容、拦截恶意请求来帮助保护Web应用。

4. 总结

文件上传漏洞是一种严重的安全风险,攻击者可以利用该漏洞执行任意代码、访问敏感数据或破坏服务器。为了

防范文件上传漏洞,开发者应当:

  • 严格验证文件类型(扩展名和MIME类型)。
  • 对文件名进行清洗,防止路径穿越和文件覆盖。
  • 使用临时存储、限制文件大小和数量,并进行文件内容扫描。
  • 对文件执行权限进行严格控制,避免上传的文件被执行。

1low难度下的File Upload漏洞利用

1,靶场提供了一个上传文件的服务,可以尝试上传一句话木马

2,将一句话木马写入1.php,然后上传文件

3,告诉了上传文件的路径,可以结合文件包含漏洞利用。这里使用蚁剑进行连接

连接成功,这里文件上传漏洞的利用十分简单攻击者满足三个条件,就能实现成功入侵:

  1. 木马上传成功,未被安全软件或firewall查杀
  2. 知道木马的文件路径
  3. 上传的木马能正常运行

low难度的靶场源码进行分析

1. 缺乏文件类型验证

  • 描述:代码没有检查上传文件的类型。这意味着攻击者可以上传任意文件,包括恶意文件(例如 .php 或 .exe 文件)。
  • 漏洞利用:攻击者可以上传恶意 PHP 文件(如 shell.php),如果上传目录没有正确配置(例如允许执行 PHP 文件),攻击者就可以通过访问该文件来执行任意代码。

2. 文件名没有消毒处理

  • 描述:文件名直接使用 basename($_FILES['uploaded']['name']) 处理,这意味着文件名中的特殊字符(如 ;, &, | 等)不会被过滤掉。攻击者可以通过上传文件名中包含特殊字符来尝试执行命令注入或路径穿越攻击。
  • 漏洞利用
    • 命令注入:如果文件名包含 shell 元字符(如 ;, &, | 等),可以通过后续的文件操作触发命令注入。
    • 路径穿越:如果文件名包含 ../,可以尝试绕过上传目录的安全限制,访问系统其他目录。

3. 上传目录的权限问题

  • 描述:代码假设上传目录 hackable/uploads/ 是安全的,但没有明确指出该目录是否有正确的权限设置。如果该目录具有执行权限(如 777),上传的 PHP 文件可以在该目录中执行。
  • 漏洞利用:攻击者上传一个 PHP Web Shell 文件并访问该文件,可以远程执行代码,进而攻击服务器。

4. 没有对文件大小进行限制

  • 描述:代码没有限制上传文件的大小。如果上传的文件过大,可能会导致服务器存储资源被耗尽,或者服务器的文件系统被攻击者滥用。
  • 漏洞利用:攻击者可以上传非常大的文件,导致服务拒绝(DoS)或占用过多存储空间。

5. 文件路径拼接不安全

  • 描述:目标路径是通过直接拼接 $_FILES['uploaded']['name'] 来生成的,没有对文件名进行规范化或安全检查。攻击者可以上传包含路径穿越字符(../)的文件名,尝试把文件上传到系统的其他敏感目录。
  • 漏洞利用:攻击者上传一个文件,文件名可能包括路径穿越,如 ../../../etc/passwd,通过这类路径攻击访问系统文件。

6. 上传过程缺乏详细的错误处理

  • 描述:如果 move_uploaded_file() 失败,系统仅输出 'Your image was not uploaded.',并没有提供具体的错误信息。这可能让攻击者更容易猜测上传失败的原因并进行反向工程。
  • 漏洞利用:如果攻击者知道文件上传失败的具体原因(例如目标路径不可写或文件类型不允许),他们可以根据这些信息调整攻击策略。

7. 目标文件路径的潜在越权

  • 描述:上传的文件没有经过额外的权限或路径验证,目标路径是直接拼接的。如果上传目录没有得到严格限制,攻击者可能通过构造特殊的路径(例如通过 .. 来“跳出”目标目录)来覆盖重要的系统文件。
  • 漏洞利用:通过上传名为 ../../../etc/passwd 的文件,攻击者有可能覆盖或访问到系统关键文件(例如 /etc/passwd),并获取系统敏感信息。

8. 没有防止多次上传相同文件名的机制

  • 描述:如果多个用户上传相同文件名的文件,它们会覆盖原有的文件。这可能导致重要数据丢失,或者攻击者上传恶意文件覆盖合法文件。
  • 漏洞利用:攻击者可以上传一个恶意文件并覆盖原本存在的合法文件,从而执行注入的恶意代码。

9. 文件内容的缺乏验证

  • 描述:文件的内容没有进行任何类型的检查。如果攻击者上传的文件内容包含恶意脚本或其他形式的攻击载体,这些文件可能会对服务器安全构成威胁。
  • 漏洞利用:上传一个图片文件,其中可能包含恶意的 EXIF 元数据或隐藏的 JavaScript 代码,利用服务器中的漏洞进行进一步攻击。

总结

这段代码的主要安全问题包括:

  • 文件类型未验证,攻击者可以上传任意文件。
  • 文件名未消毒处理,可能导致路径穿越、命令注入等问题。
  • 上传目录权限不明确,上传的恶意文件可能被执行。
  • 缺乏文件大小限制,导致可能的资源耗尽攻击。
  • 缺乏错误信息处理,攻击者可能根据错误信息进行反向工程。

通过这些漏洞,攻击者可以实现各种攻击,例如远程代码执行(RCE)、信息泄露、服务拒绝(DoS)或文件覆盖攻击等。

2medium难度下的File Upload漏洞利用

1,如果按low难度的方式去文件上传是失败的,报错信息提示只允许传图片文件

2,这里的思路比较简单,給网站挂上burp suite的proxy,一句话木马文件命名为1.png,上传木马文件并在burp suite截获文件

3,右键发送到repeater模块,然后给filename改为1.php

4,然后就可以看到渲染页面render显示文件上传成功了,并且告诉了路径

5,使用蚁剑进行连接,成功获得网站的webshell

medium难度的靶场源码进行分析

在这段代码上传功能已经做了一些基础的文件类型和大小限制,但仍然存在潜在的漏洞和局限性。

1. 文件类型限制

if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) ) {

有效性:

  • 文件类型检查:代码通过检查文件的 MIME 类型 ($uploaded_type) 来限制上传的文件类型,只允许 JPEG 和 PNG 格式的图片。这是一种防范非图片文件上传的基本手段,可以避免一些常见的攻击(如上传 PHP 文件等)。

局限性:

  • 不可靠的 MIME 类型:$_FILES['uploaded']['type'] 是由客户端传递的,攻击者可以伪造这个值。例如,攻击者可以通过修改请求的 Content-Type 头来上传 PHP 文件,但将 MIME 类型伪装成 image/jpeg 或 image/png,从而绕过该检查。
  • 依赖客户端检测:由于 MIME 类型是客户端发送的,攻击者可以篡改请求头,绕过该限制。PHP 的 $_FILES['uploaded']['type'] 并不总是可信的,因此只能作为一种辅助验证,而不能作为唯一的防线。

2. 文件大小限制

$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
if( $uploaded_size < 100000 ) {

有效性:

  • 文件大小限制:代码限制了上传文件的最大大小为 100,000 字节(即约 100 KB)。这对于防止上传过大的文件(如高分辨率的图片或视频)是有效的,可以防止攻击者通过上传大型文件耗尽服务器资源。

局限性:

  • 相对宽松的大小限制:虽然 100 KB 对于普通图片文件来说是合理的限制,但对于一些轻量级的恶意文件(如小型的 PHP Web Shell)而言,这个限制可能过于宽松。攻击者仍然可以上传一些小型恶意文件(如包含恶意代码的图片或压缩文件等)。
  • 没有对文件大小的服务器级别限制:尽管在代码中设置了上传文件大小限制,但如果 PHP 的配置文件(php.ini)没有设置上传文件的最大大小,攻击者仍然可以通过服务器的配置绕过此限制。例如,upload_max_filesize 和 post_max_size 配置项的设置可能允许上传比这个限制更大的文件。如果 PHP 配置不当,客户端限制就无法生效。

3. 文件名处理

$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

有效性:

  • 使用 basename() 过滤文件路径:通过使用 basename() 函数,代码试图避免路径穿越攻击(例如,上传 ../../etc/passwd 文件)。这可以确保文件名不包含目录路径,防止上传的文件写入其他系统目录。

局限性:

  • 文件名可能存在恶意字符:虽然 basename() 可以防止路径穿越攻击,但它没有对文件名本身进行过滤。如果上传的文件名包含恶意字符(如空格、&、;、$ 等),可能会导致命令注入或其他类型的漏洞。例如,上传文件名为 shell.php; rm -rf / 的文件,可能会导致攻击者通过命令注入控制服务器。
  • 文件扩展名未验证:上传的文件扩展名没有被验证或限制。即使文件名是 image.jpg,但文件的内容可能并不是图像文件。攻击者可能上传一个 PHP 脚本文件,修改扩展名为 .jpg 或 .png,从而绕过文件类型检查。

4. 文件内容验证

  • 没有对文件内容进行有效验证:代码只检查了文件的 MIME 类型和大小,并没有验证文件的实际内容。例如,一个文件可能被伪装成 image/jpeg 类型,但它的实际内容可能是一个包含恶意代码的文件(如嵌入了恶意的 PHP 代码的图片)。

局限性:

  • 缺乏更严格的内容验证:攻击者可以上传伪装成图片的恶意文件,利用文件的隐蔽性执行攻击。例如,通过上传带有恶意 PHP 代码的图片文件,如果上传目录的权限配置不当,恶意代码可能会被执行。
  • 没有使用图像库进行验证:可以使用 PHP 的图像处理函数(如 getimagesize())来验证文件是否真的是图像。即使文件扩展名是 .png 或 .jpg,通过这种方式检查文件内容可以确保文件符合预期的图像格式,而不是伪装的恶意文件。

5. 上传目录权限

  • 上传目录权限未明确控制:尽管代码中指定了目标路径,但没有明确提到该上传目录的权限配置。如果上传目录的权限过于宽松,允许执行 PHP 文件(如 777 权限),攻击者可以上传并执行恶意的 PHP Web Shell,控制服务器。

局限性:

  • 潜在的执行权限问题:如果上传目录没有进行严格的权限控制,上传的文件可能被执行。即使文件本身是图像文件,如果目录配置错误,攻击者仍然可以上传并执行伪装成图像的 PHP 脚本。

总结:有效性与局限性

有效性:

  • 文件类型和大小限制:通过 MIME 类型和文件大小的限制,代码能够有效地阻止部分不符合条件的文件上传(如非图片文件、过大文件等)。
  • 文件名路径防范:通过 basename() 防止路径穿越,确保文件被上传到预定目录。

局限性:

  • 不可信的 MIME 类型:客户端传递的 MIME 类型可以被篡改,无法完全依赖其进行验证。
  • 缺乏对文件内容的严格检查:未对上传的文件内容进行验证,攻击者可以伪装恶意文件绕过上传限制。
  • 上传目录权限不明确:如果上传目录没有严格的权限配置,攻击者可能上传并执行恶意文件。
  • 文件名不安全:文件名可能包含恶意字符,可能导致命令注入或路径执行问题。
  • 大小限制可能过于宽松:虽然设置了文件大小限制,但该限制可能不足以防止一些小型恶意文件上传。

3high难度下的File Upload漏洞利用

1,high难度下对文件上传的限制与过滤更加严格,还是挂上burp suite的proxy,一句话木马文件命名为1.png,上传木马文件并在burp suite截获文件

2,然后送入burp suite模块,尝试使用和medium靶场一样的操作方式

3,上传失败,说明改文件后缀这种简单的绕过方式是无效的。那么这个时候的思路就需要比较开阔,可以通过命令行制作图片木马文件【CTF】图片马制作-CSDN博客

win+R 、 cmd,输入 copy 图片文件名/b+一句话木马文件名/a 制作的图片马文件名

可以使用010editor查看图片木马是否制作成功

上传制作的图片木马文件

4,使用蚁剑根据暴露的上传的文件路径连接图片马,测试连接失败

此时是不能使用蚁剑连接的,因为蚁剑的原理是向上传文件发送包含参数(连接密码)的post请求,通过控制参数来执行不同的命令。这里服务器将木马文件解析成了图片文件,因此向其发送 post 请求时,服务器并不会执行相应命令

5,接下来就需要将这张图片木马当做php来执行,在DVWA靶场里面可以结合File Inclusion文件包含漏洞网站利用,构造 payload:

file://D:/phpstudy_pro/WWW/DVWA-master/hackable/uploads/1.png

一句话木马由此成功被解析,这个时候再使用蚁剑进行连接

6,除了利用该靶场的文件包含漏洞,还可以使用该靶场的命令执行漏洞对文件进行改名,最后再用webshell管理工具蚁剑进行连接

high难度的靶场源码进行分析

有效性:

  1. 文件扩展名检查
    • 代码限制上传文件的扩展名仅为 .jpg, .jpeg, .png,这有效地防止了上传其他类型的文件(如 .php、.html、.exe 等可能含有恶意代码的文件)。
  2. 文件大小限制
    • 代码对上传文件的大小进行了限制,文件必须小于 100 KB。这有助于防止攻击者上传过大的文件,减少对服务器资源的消耗(如磁盘空间和带宽)。
  3. 图像文件验证
    • 使用 getimagesize() 函数检查上传的文件是否为有效的图像文件。即使文件扩展名正确,getimagesize() 仍然可以确保文件的实际内容是图像。这可以防止一些恶意脚本伪装成图片文件上传。

局限性:

  1. 扩展名验证不充分
    • 文件扩展名检查只能防止常见的扩展名伪造攻击(例如 .php 攻击),但是攻击者可以上传其他伪装文件(如 .jpg.php 或 .png.php)。如果文件名后缀包含多个点(例如 evil.jpg.php),就可能绕过扩展名检查。
  2. 图像验证有限
    • getimagesize() 只能验证文件是否为有效的图像文件,但不能确保文件本身不包含恶意代码。例如,攻击者可以上传带有 PHP 代码的图片文件(如通过包含在图片末尾的恶意代码)。如果上传目录具有执行权限,恶意代码可能会被执行。
  3. 缺乏文件名消毒
    • 上传的文件名没有经过严格的消毒处理。虽然使用了 basename() 防止路径穿越攻击(例如 ../../etc/passwd),但文件名仍然可能包含恶意字符(如空格、分号等)并导致其他安全问题(如命令注入)。
  4. 上传目录权限问题
    • 如果上传目录没有严格的权限控制(如不允许执行文件),即使上传的是图像文件,攻击者仍可能通过其他方式上传恶意文件(如上传包含 PHP 代码的图片)。确保目录权限设置为只允许写入且禁止执行是必要的。
  5. 服务器级别的限制未提及
    • 代码中对文件大小做了限制,但如果 PHP 配置(如 upload_max_filesize 和 post_max_size)不当,攻击者仍然可以上传更大的文件,绕过代码中的限制。

四,对high难度的靶场源码进行代码审计,分析其安全性能

1. CSRF 防护

checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

  • 优点
    • 代码使用了 Anti-CSRF token 来防止跨站请求伪造攻击(CSRF)。通过比对用户提交的 token 和服务器存储的 token,能够有效阻止恶意网站通过用户的浏览器发起未经授权的文件上传请求。
  • 潜在风险
    • 需要确保 generateSessionToken() 和 checkToken() 函数的实现是安全的。尤其是生成和验证 token 时,必须确保 token 足够复杂,并且使用 HTTPS 来防止中间人攻击。
    • 如果 token 没有正确保护(如容易被猜测或通过 XSS 漏洞泄露),攻击者仍然可能绕过 CSRF 防护。

2. 文件扩展名和 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 ) )

  • 优点
    • 文件的扩展名、大小、类型都经过了验证,并且使用了 getimagesize() 来确认上传的文件是否为有效的图片。这能有效防止一些常见的上传漏洞,比如上传伪造的 PHP 文件。
  • 潜在问题
    • 扩展名验证不足:仅通过扩展名和 MIME 类型检查文件类型,并不足够强大。攻击者可以尝试上传带有恶意代码的图片文件(例如,PHP Web Shell 伪装成图片),绕过扩展名检查。攻击者还可以上传一个包含 PHP 代码的图片文件(例如 image.php.jpg),并利用文件上传目录的错误配置执行该代码。
    • getimagesize() 限制:getimagesize() 只能检查文件的图像头信息,而不能确保文件内容的安全性。攻击者可以构造一个带有恶意代码的有效图像文件。
    • MIME 类型伪造:$_FILES['uploaded']['type'] 是由客户端提供的,可以被伪造。攻击者可能会通过修改请求中的 MIME 类型来绕过服务器的验证(例如,将文件的 MIME 类型伪造为 image/jpeg)。

3. 文件重命名

$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;

  • 优点
    • 使用 md5() 和 uniqid() 生成唯一的文件名,这样可以有效避免文件名冲突,并防止攻击者通过上传恶意文件并利用文件名攻击(例如文件名包含路径穿越 ../)。
  • 潜在问题
    • MD5 不够安全:虽然 MD5 在这里用来生成文件名,但 MD5 已经被广泛认为不安全,因为它容易碰撞。虽然碰撞攻击在这种简单的场景中不太可能,但使用更安全的哈希算法(如 SHA-256)会更好。

4. 图片重新编码(去除元数据)

imagejpeg( $img, $temp_file, 100);

  • 优点
    • 通过重新编码图片来去除元数据(EXIF、XMP 等),这有助于防止攻击者通过在图片元数据中嵌入恶意代码来进行攻击。
  • 潜在问题
    • 图片处理不完全安全:尽管重新编码图片有助于去除元数据,但如果没有使用更为强大的工具(如 Imagick,而不是 GD),仍然存在一定的风险。GD 库处理图片时的漏洞可能被攻击者利用。
    • 如果图片中嵌入了恶意内容(例如,特殊的图像文件格式漏洞),重新编码并不能完全消除风险。

5. 文件移动和权限控制

if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) )

  • 优点
    • 使用 rename() 将文件从临时目录移动到目标目录,避免了使用 move_uploaded_file(),这减少了某些可能的权限问题。
  • 潜在问题
    • 上传目录权限问题:代码没有明确提到上传目录的权限设置。若上传目录没有适当的权限控制,攻击者可以通过上传的文件执行恶意代码。因此,上传目录应设置为 禁止执行(noexec),并且应限制上传目录的访问权限。
    • 不安全的目录:如果目标目录 (hackable/uploads/) 位于 Web 根目录下且可被直接访问,上传的文件可能会被直接访问和执行(如果是 PHP 脚本或其他可执行文件)。建议将上传目录放在 Web 根目录之外,或者对文件类型进行进一步的检查。

6. 临时文件删除

if( file_exists( $temp_file ) )
    unlink( $temp_file );

  • 优点
    • 在上传操作完成后删除临时文件,这是一个好的做法,确保不留下不必要的文件。
  • 潜在问题
    • 删除失败未处理:如果 unlink() 删除临时文件失败,代码没有处理这个情况。如果出现失败,可能会留下垃圾文件。可以考虑增加错误处理逻辑,确保临时文件始终被清理。

7. 文件大小限制

( $uploaded_size < 100000 )

  • 优点
    • 限制上传文件大小为 100 KB,有助于防止上传过大文件,避免占用服务器过多的资源。
  • 潜在问题
    • PHP 配置问题:这段代码仅限制了文件大小,但 PHP 配置文件(php.ini)中的 upload_max_filesize 和 post_max_size 配置项也必须匹配。如果这些设置较大,攻击者可能绕过代码中的限制。因此,除了代码中的限制,服务器配置也需要严格控制文件大小。

总结:

优点:

  • CSRF 防护:通过 Anti-CSRF token 防止伪造的请求。
  • 文件类型和大小检查:有效限制上传文件的类型和大小。
  • 文件名唯一化:通过哈希值生成唯一文件名,避免文件名冲突和路径穿越问题。
  • 去除元数据:通过重新编码图片去除可能的恶意元数据。

潜在风险:

  • 扩展名和 MIME 类型伪造:仅依赖扩展名和 MIME 类型检查并不足够,攻击者可能伪造文件类型绕过验证。
  • 图像处理不足:尽管重新编码去除了元数据,但仍然存在图像格式漏洞的风险。
  • 文件权限问题:上传目录如果未严格配置权限,上传的文件可能会被执行。
  • MD5 安全性问题:使用 MD5 生成文件名可能存在哈希碰撞的风险,应考虑使用更安全的哈希算法。
  • 临时文件删除问题:临时文件删除失败未处理。

改进建议:

  1. 加强文件类型检查:除了扩展名和 MIME 类型,使用更强的内容验证,如通过 finfo_file() 或 exif_imagetype() 函数进一步验证文件类型。
  2. 目录权限控制:确保上传目录的权限设置为只允许写入,禁止执行文件。
  3. 使用更安全的哈希算法:使用 SHA-256 或其他更强的哈希算法代替 MD5。
  4. 服务器配置:确保 PHP 配置中的文件大小限制与代码中的限制一致,避免绕过。
  5. 图像处理库:考虑使用更强大的图像处理库,如 Imagick,以提高安全性。