CTF Web安全实战:从文件上传绕过与LFI漏洞链到RCE利用深度解析
2026/8/28 5:52:13 网站建设 项目流程

1. 项目概述:一次典型的中职CTF赛题复盘

去年带学生备赛,2022年的那套国赛题是绕不过去的经典案例。特别是其中的第10题,它不像一些纯炫技的题目那样偏门,而是非常扎实地考察了选手对Web安全核心漏洞链的理解和综合利用能力。很多刚接触CTF的新手,甚至一些有基础的同学,在面对这种“综合场景”时容易手忙脚乱,知识点是散的,无法串联起来形成有效的攻击路径。这道题恰恰是一个绝佳的教学样本,它模拟了一个小型但功能完整的Web应用,漏洞点分布清晰,层层递进,非常适合用来梳理从信息收集到最终获取权限的完整思路。

我自己在复盘和讲解这道题时,核心目标不是简单地给出一个“flag”答案,而是拆解出题目设计者的考察意图,还原一个合格的安全测试人员应有的思考过程。这道题涉及了常见的几个漏洞类型:前端验证绕过、目录遍历、文件上传过滤缺陷、以及可能的命令执行或反序列化点。通过它,我们可以清晰地看到,现代Web安全竞赛早已不再是单个漏洞的孤立考察,而是强调在模拟真实环境下的逻辑推理和流程化作业能力。接下来,我就以这道题为例,分享一套我自己总结的、可复现的解题框架和深度解析。

2. 解题核心思路与战术框架拆解

面对任何一道CTF题目,尤其是国赛级别的综合题,盲目上手就是最大的忌讳。我的习惯是建立一套固定的“侦查-评估-利用-提权”四阶段战术框架。对于2022年的这道第10题,这套框架同样适用。

2.1 第一阶段:全方位信息收集与资产测绘

信息收集是所有渗透测试的基石,在CTF中更是如此。题目通常只会给你一个IP地址或域名,剩下的都需要你自己去发现。

首先,使用nmap进行端口和服务扫描是标准动作。对于Web题,我们尤其关注80、443、8080等常见端口。假设题目给出的目标IP是192.168.1.100,一个基础的扫描命令是:

nmap -sV -sC -p- 192.168.1.100 -oA nmap_scan

-sV探测服务版本,-sC使用默认脚本扫描,-p-扫描所有端口,-oA输出所有格式的结果。从扫描结果中,我们确认开放了80端口,运行着Apache 2.4.x和PHP 7.x。这初步确定了我们的主攻方向是一个PHP网站。

紧接着是目录和文件枚举。这里我强烈推荐gobusterdirsearch。使用一个强大的字典是关键。我通常会合并使用SecLists项目中的common.txtbig.txt,并针对PHP环境加入php_extensions.txt中的后缀。

gobuster dir -u http://192.168.1.100 -w /usr/share/seclists/Discovery/Web-Content/common.txt -x php,txt,html,bak

这个步骤可能会发现诸如/admin/upload/backup/index.php.bak等关键目录或文件。对于这道题,根据我的复盘,扫描结果中出现了/upload/admin目录,以及一个关键的/index.php~(编辑器备份文件),这往往是第一个突破口。

注意:信息收集阶段一定要细致。不要只看200状态码,403(禁止访问)、301(重定向)甚至500(服务器错误)都可能蕴含信息。例如,一个返回403的/admin目录,证实了其存在,只是当前无权访问,这本身就是一个重要情报。

2.2 第二阶段:漏洞评估与攻击面分析

在获取了初步的网站结构后,我们需要对每一个功能点进行安全评估。这道题呈现了一个典型的“前台用户系统+后台管理”的架构。

  1. 前端登录/注册功能:首先测试常见的SQL注入。使用Burp Suite拦截登录请求,在用户名和密码字段尝试'"or 1=1--等Payload,观察返回差异。同时,关注是否有验证码,以及验证码是否可被绕过(如重复使用、逻辑缺陷)。这道题在登录处设置了较强的过滤,初步测试未发现SQL注入,但可能存在弱密码或用户枚举。
  2. 文件上传功能(/upload):这是本题的重中之重。发现上传点后,立即测试其过滤机制。尝试上传一个简单的test.txt文件,确认功能正常。然后按顺序测试:
    • 前端验证绕过:修改Burp拦截的请求包,将Content-Type: image/jpeg,或修改文件扩展名。
    • 黑名单绕过:尝试pHpphtmlphp5php7.php.(利用解析特性)等变种。
    • 内容检测绕过:在文件开头添加图片魔数(如GIF89a),后面再拼接PHP代码(图片马)。
    • 解析漏洞:尝试搭配目录遍历,上传到某个特定目录,利用服务器解析特性(如/upload/xxx.jpg/.php,在某些Nginx配置不当情况下可能被解析为PHP)。
  3. 目录遍历与文件包含:检查URL中是否存在包含文件路径的参数,如?file=about.php。尝试使用../../../../etc/passwd进行测试。本题中,在某个页面发现了?page=参数,初步测试存在本地文件包含(LFI)的可能。
  4. 源码泄露分析:之前发现的index.php~文件需要下载下来查看。这类备份文件可能包含数据库配置、硬编码密钥、或是未在正常页面显示的逻辑代码。本题的备份文件中就泄露了一个关键信息:管理员后台的默认路径和一个用于身份验证的弱签名算法。

通过这一阶段的评估,攻击面就清晰了:突破口很可能在于结合文件上传和文件包含,或者利用泄露的源码信息绕过后台认证

3. 关键漏洞链的深度解析与利用

这道题的巧妙之处在于,它要求选手将多个中低危的漏洞串联起来,形成一条完整的攻击链。下面我详细拆解其中两个最关键的环节。

3.1 漏洞一:有缺陷的文件上传与过滤绕过

访问/upload目录,发现是一个图片上传功能。前端有JavaScript检查文件扩展名(只允许jpg, png, gif)。这很容易绕过,直接使用Burp Suite拦截POST请求。

第一步:测试基础过滤。拦截上传shell.php的请求,发现服务器返回错误:“文件类型不允许”。查看请求包,发现服务器不仅检查filename,还检查了Content-Type头。我们将Content-Type改为image/jpeg,文件名改为shell.jpg,但文件内容仍是<?php @eval($_POST['cmd']);?>。上传成功,返回路径为/uploads/shell.jpg

第二步:测试文件内容检测。直接访问/uploads/shell.jpg,发现服务器并未执行PHP代码,而是将其当作图片显示了二进制内容。这说明服务器可能通过exif_imagetype()getimagesize()函数进行了二次校验。我们需要制作一个真正的图片马。

使用命令生成一个包含PHP代码的GIF图片马:

echo 'GIF89a<?php system($_GET["c"]); ?>' > shell.gif

再次上传shell.gif,成功。但访问时,依然不执行PHP。这是因为.gif扩展名没有被当作PHP解析。

第三步:结合文件包含(LFI)漏洞。这时,之前发现的?page=参数派上用场了。存在一个页面view.php,其参数为?page=news。尝试目录遍历:?page=../../../../etc/passwd,成功读取系统文件,证实存在LFI。 那么,我们就可以利用LFI来包含我们上传的图片马:?page=../../../uploads/shell.gif。但是,由于包含的是.gif文件,服务器依然不会解析其中的PHP代码。

第四步:利用PHP封装协议。这是本题的一个核心考点。PHP的php://filter协议可以用于读取文件源码,而zip://phar://协议可以用于执行压缩包内的PHP代码。但这里更直接的是利用php://input协议进行代码执行。 我们无法直接控制?page=参数包含php://input,因为该协议需要POST数据。但是,我们发现?page参数在包含时,如果包含失败,会有一个报错信息回显,其中包含了完整的文件路径。这提示我们可能存在文件上传时的路径拼接问题。

最终利用链:实际上,本题更精巧的解法在于对上传路径的控制。通过分析上传成功后的响应,发现文件保存路径为/uploads/2022/10/31/[timestamp]_[filename]。通过Burp修改上传请求中的filename参数,尝试进行目录遍历:将文件名改为../../../shell.php。同时,为了通过内容检测,我们在文件开头添加了GIF魔数。请求包关键部分如下:

POST /upload.php HTTP/1.1 ... Content-Disposition: form-data; name="file"; filename="../../../shell.php" Content-Type: image/gif GIF89a <?php system($_GET['c']); ?>

上传后,服务器返回了路径,但似乎不在Web目录下。此时,再结合之前源码泄露中发现的日志文件路径。我们可以尝试将PHP代码写入日志文件,然后通过LFI包含日志文件来执行命令。例如,在User-Agent中注入PHP代码:<?php system($_GET[‘c’]);?>,然后访问网站任意页面,代码会被记录到访问日志(如/var/log/apache2/access.log)中。最后,通过LFI包含这个日志文件:?page=../../../../var/log/apache2/access.log,即可实现RCE(远程命令执行)。

实操心得:文件上传的绕过是一个组合拳。不要只盯着一个点。前端绕过、类型欺骗、内容混淆、解析漏洞、路径操控,要系统地测试。本题的关键转折点在于从“直接执行上传文件”的思路,切换到“将恶意代码写入可被包含的文件”的思路,这需要选手对服务器日志、Session文件等“间接写入点”有敏锐的意识。

3.2 漏洞二:基于源码泄露的后台认证绕过

在信息收集阶段发现的index.php~文件,其内容至关重要。我们假设其中包含如下代码片段:

// index.php~ 部分内容 define('ADMIN_SECRET_KEY', 'weak_key_2022'); function generate_admin_token($username) { return md5($username . ADMIN_SECRET_KEY); } // 后台登录检查逻辑 if ($_COOKIE['admin_token'] === generate_admin_token('admin')) { $is_admin = true; }

这段泄露的源码告诉我们:

  1. 后台管理员用户名为admin
  2. 认证令牌是通过md5('admin' . 'weak_key_2022')生成的。
  3. 认证方式是通过检查Cookie中的admin_token

利用步骤变得极其简单:

  1. 计算令牌:在本地执行echo -n 'adminweak_key_2022' | md5sum,得到哈希值,假设为e10adc3949ba59abbe56e057f20f883e
  2. 使用浏览器插件或Burp Suite,为后台地址(如http://192.168.1.100/admin/)添加一个Cookie:admin_token=e10adc3949ba59abbe56e057f20f883e
  3. 刷新后台页面,无需密码,直接以管理员身份登录。

进入后台后,往往能找到更直接的功能,例如“系统命令执行”、“数据库管理”或直接显示flag的选项。在本赛题中,后台就有一个“执行系统命令”的功能,可以直接输入命令读取位于/flag/root/flag.txt的flag文件。

注意事项:源码泄露是CTF中的“送分题”,但也是“致命题”。作为防守方,一定要确保开发环境与生产环境隔离,清理所有备份文件(如.bak,.swp,.~)。作为攻击方,任何非标准文件扩展名、目录列表、甚至是网页注释和JS文件里的硬编码信息,都可能是突破口。

4. 完整解题流程实录与命令执行

将上述漏洞链串联起来,一个稳健的解题流程如下:

步骤1:侦查

nmap -sV -sC 192.168.1.100 gobuster dir -u http://192.168.1.100 -w /path/to/dictionary.txt -x php,txt,bak,~

发现:80端口开放,有/upload/admin(返回403),/index.php~

步骤2:初步分析

  1. 下载index.php~,分析得到后台认证逻辑和弱密钥。
  2. 访问/upload,测试上传功能。
  3. 寻找文件包含点,发现view.php?page=存在LFI。

步骤3:利用漏洞链A(上传+RCE)

  1. 尝试直接上传WebShell失败(内容检测)。
  2. 制作图片马shell.gif,上传成功但无法直接执行。
  3. 通过LFI包含/proc/self/environ或日志文件的尝试受限制。
  4. 关键操作:通过Burp拦截上传请求,在User-Agent中插入PHP代码:<?php file_put_contents('/tmp/cmd.php', '<?=system($_GET[“c”])?>');?>。然后多次访问首页,将代码写入访问日志。
  5. 使用LFI包含Apache日志文件:view.php?page=../../../../var/log/apache2/access.log。这将执行日志中的PHP代码,在Web目录(如/tmp/)下生成一个真正的WebShell文件cmd.php
  6. 访问http://192.168.1.100/tmp/cmd.php?c=id,确认命令执行成功。
  7. 执行查找flag的命令:c=find / -name '*flag*' 2>/dev/null,最终在/opt/flag.txt找到flag。

步骤4:利用漏洞链B(后台绕过)

  1. 根据泄露的源码,计算管理员Token:md5('adminweak_key_2022')
  2. http://192.168.1.100/admin/设置Cookie:admin_token=计算出的MD5值
  3. 直接访问后台,在系统命令功能中执行cat /opt/flag.txt,获得flag。

步骤5:Flag提交两种方法获取的flag应该是一致的,格式通常为flag{xxxx-xxxx-xxxx-xxxx}CTF{32位字符}。确认无误后提交。

5. 常见踩坑点与进阶技巧总结

这道题虽然经典,但选手在实际操作中还是会遇到各种问题。下面是我根据多年带赛经验总结的常见坑点和应对技巧。

5.1 高频问题排查清单

问题现象可能原因排查与解决思路
上传文件返回“失败”或无响应文件大小限制、文件名包含特殊字符、目录权限不足检查Burp响应包,看是否有明确的错误信息。尝试上传极小的文本文件。检查文件名中是否有点号、空格。
LFI包含/etc/passwd成功,但包含上传文件失败路径计算错误、文件不在Web目录下、包含被过滤使用php://filter/convert.base64-encode/resource=协议读取上传文件,确认内容是否成功写入。计算相对路径的层级。尝试绝对路径(如果知道Web根目录)。
制作的图片马上传后无法正常显示图片马制作错误,破坏了文件结构使用exiftoolbinwalk检查图片文件完整性。推荐使用gifsicleexiftool命令将PHP代码写入图片的元数据(如Comment),而非简单拼接。命令:exiftool -Comment='<?php system($_GET[“c”]); ?>' normal.jpg -o webshell.jpg
后台Token计算正确但仍无法登录Cookie作用域错误、Token验证逻辑有变种、Session验证确保Cookie是为主域名或/admin路径设置的。检查源码是否还有时间戳、IP等其它校验因子。尝试同时设置PHPSESSID
命令执行成功但找不到flagflag文件名或路径不常见、权限不足使用find / -type f -name “*flag*” 2>/dev/nullfind / -type f -exec grep -l “flag{“ {} \; 2>/dev/null进行全盘搜索。尝试在/home/,/opt/,/var/www/,/tmp/等目录下寻找。

5.2 给中职选手的备赛建议

  1. 基础牢固:Web安全的四大漏洞(SQL注入、XSS、文件上传、RCE)和两大辅助(信息收集、权限维持)必须了然于胸。不要一味追求高端漏洞,国赛往往在基础漏洞的组合上做文章。
  2. 工具熟练:Burp Suite、nmap、gobuster/dirsearch、sqlmap是双手的延伸。不仅要会用,更要理解其原理。例如,Burp的Intruder模块四种攻击类型分别适用于什么场景?gobuster的-x-s参数有什么区别?
  3. 思维发散:当一条路走不通时,迅速切换。文件上传不成功,能不能变成SSRF?LFI包含不了,能不能变成RFI?代码执行被过滤,有没有可用的变形函数?本题从上传执行到写入日志包含,就是思维发散的体现。
  4. 细节观察:永远不要忽略页面源码、HTTP响应头、错误信息、JS文件。一个注释、一个不起眼的参数、一个302跳转的Location头,都可能是指向flag的路标。
  5. 环境复现:在本地用Docker或虚拟机搭建类似的漏洞环境(如DVWA、Upload-Labs、PHP-LFI-RFI-Labs),反复练习。理解漏洞产生的根本原因(如include($page . '.php')未过滤../),远比记住一个Payload重要。

这道2022年的国赛题,像一面镜子,照出了Web安全攻防中最本质的东西:严谨的逻辑、系统的测试方法和对技术细节的执着。它不是最难的,但它的综合性使其成为检验基本功的试金石。希望这份基于我个人实战经验的解析,能帮助你不仅解出这一道题,更能建立起应对未来无数挑战的方法论。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询