文件上传漏洞
1. 定义
文件上传漏洞 发生在 Web 服务器允许用户在未经充分验证(如文件名、类型、内容或大小)的情况下,将文件上传至其文件系统时。
最严重的后果是 远程代码执行 (Remote Code Execution, RCE):攻击者上传一个脚本(如 shell.php),然后该脚本在服务器上被执行。
2. 技术原理
服务器通常根据文件扩展名或 MIME 类型来决定如何处理文件。
- 扩展名绕过: 攻击者将
shell.php重命名为shell.php.jpg或利用零字节截断shell.php%00.jpg。 - MIME 伪造: 在发送 PHP 脚本时,将 HTTP 标头中的
Content-Type修改为image/jpeg。 - 多语言型文件 (Polyglots): 创建一个合法的图像文件,但在其元数据 (EXIF) 中包含有效的 PHP 代码。
如果服务器将此类文件保存到公开目录(如 /uploads),且服务器配置允许在该目录下执行 PHP/ASP 文件,那么访问 site.com/uploads/shell.php 就会触发恶意程序的执行。
3. 攻击流程 (Web Shell)
sequenceDiagram
participant Attacker as 攻击者
participant Server as 服务器
participant FS as 文件系统
Attacker->>Server: POST /upload (将 shell.php 重命名为 shell.jpg 上传)
Note right of Attacker: 内容: <?php system($_GET['cmd']); ?>
Server->>Server: 检查扩展名 (.jpg)? 通过。
Server->>FS: 保存至 /var/www/uploads/shell.jpg
Attacker->>Server: GET /uploads/shell.jpg
Note right of Attacker: 服务器执行了 PHP,因为<br/>配置允许 .jpg 以脚本方式运行<br/>或文件被重命名回了 .php
Server-->>Attacker: 返回命令执行结果4. 真实案例:ImageTragick (2016)
目标: 使用 ImageMagick 的数千个网站。 漏洞类别: 文件处理 / 命令注入 (CVE-2016-3714)。
漏洞背景: ImageMagick 是一个被广泛使用的图像处理库(当时包括 Facebook 和 Yahoo 在内的许多网站都在使用它来缩放用户上传的照片)。 它在处理 SVG (矢量图) 文件时存在缺陷:支持通过“委托 (delegates)”执行 Shell 命令。
攻击过程: 攻击者上传了一个精心构造的图像文件(看起来是 .jpg 或 .mvg),内容如下:
fill 'url(https://example.com/image.jpg"|ls "-la)'当服务器尝试“缩放”这张图片时,ImageMagick 执行了 ls -la 命令。这意味着攻击者只需上传一张头像就能实现完全的远程代码执行。
5. 深度防御策略
A. 扩展名白名单 (Allowlist)
绝不使用黑名单(如禁止 .php, .exe)。攻击者总能找到绕过方法,如 .php5, .phtml 等。
- 白名单机制: 仅接受特定的安全扩展名:
.jpg,.png,.pdf。
B. 内容校验 (魔数 Magic Bytes)
不要相信文件扩展名或 Content-Type 标头(这些都是用户可控的)。
- 机制: 读取文件的前几个字节(魔数)来验证其真实类型。
- JPEG =
FF D8 FF - PNG =
89 50 4E 47
- JPEG =
- 如果魔数与扩展名不匹配,则拒绝文件。
C. 文件名随机化
不要使用用户提供的原始文件名(如 my_vacation.jpg)。
- 防御措施: 在存储时将文件重命名为 UUID (如
f47ac10b...jpg)。这可以防止覆盖关键系统文件,并能防御部分路径遍历尝试。
D. 存储于 Web 根目录之外
将上传的文件存储在 Web 服务器无法直接访问的目录中(例如 S3 桶或私有文件夹)。通过一个读取文件流的控制器来间接提供文件内容。这能从根源上防止服务器直接“执行”上传的文件。
