1. 项目概述:一次典型的中职CTF赛题复盘
最近在整理过去的竞赛资料,翻到了2022年中职网络空间安全国赛的一道题目,编号是试题7。这道题在当时赛场上给不少选手制造了麻烦,但它的设计思路非常经典,涵盖了Web安全中几个核心的知识点。今天,我就以这道题为例,和大家一起拆解一下CTF(Capture The Flag)竞赛中Web类题目的常见套路和解题逻辑。我的解析仅代表个人在实战中的理解和建议,希望能给正在学习网络安全、准备竞赛的朋友们提供一个清晰的思考路径。
CTF比赛,尤其是中职、高职阶段的赛事,题目往往不会追求最新的、最偏门的漏洞,而是侧重于考察选手对基础知识的扎实掌握和灵活运用能力。这道2022年的国赛题就是一个很好的例子,它没有用复杂的框架或生僻的CVE,而是将信息泄露、代码审计、命令执行这几个基础环节串联起来,构建了一个完整的攻击链。对于初学者而言,吃透这类题目,远比去追逐那些“炫技”的0day更有价值。接下来,我们就一步步走进这道题,看看如何从题目描述和给定的环境(通常是一个Web地址)中,抽丝剥茧,找到最终的flag。
2. 赛题环境初探与信息收集
2.1 题目描述分析与初始思路
拿到任何CTF题目,第一步永远是仔细阅读题目描述。虽然我们无法还原当时的完整题目文本,但根据“试题7”的常见模式和后续解题过程反推,这类题目通常会提供一个简单的网站地址(例如http://target_ip:port),并附上一句模糊的提示,比如“找到隐藏的flag”或“获取服务器上的秘密信息”。题目本身可能没有任何前端交互,就是一个静态页面,也可能是一个存在功能缺陷的简单应用。
我的建议是,立即打开浏览器访问目标地址。首先用眼睛快速扫描页面内容,包括前端HTML源码(右键查看源代码)。不要放过任何注释、隐藏的表单、不起眼的链接,甚至是图片的alt属性。很多入门题喜欢把提示直接写在HTML注释里。接着,使用浏览器开发者工具(F12)查看网络请求、检查JS文件。同时,用dirsearch、gobuster这类目录扫描工具进行后台目录爆破,寻找像/admin、/backup、/src、/.git这类可能泄露信息的路径。这是信息收集的“标准作业流程”,必须形成肌肉记忆。
注意:在比赛环境中,使用扫描工具要注意频率,避免触发WAF(Web应用防火墙)规则或被封IP。通常可以加上延迟参数,例如
dirsearch -u http://target -e php,html,bak --delay=1。
2.2 关键信息发现与源码泄露
在对这道模拟题进行信息收集时,我们假设发现了一个关键线索:在网站根目录下,存在一个名为robots.txt的文件。访问后,其内容显示:
User-agent: * Disallow: /source.zip这是一个非常明显的提示,它告诉我们有一个/source.zip文件被故意“隐藏”了起来。下载并解压这个ZIP文件,我们得到了网站的源代码。这步操作在CTF中称为“源码泄露”,是出题人降低难度、引导选手进入代码审计阶段常见的手法。
解压后,我们发现这是一个简单的PHP应用目录结构,通常包含index.php、login.php、admin.php等文件。我们的主战场立刻从黑盒测试转向了白盒的代码审计。此时,应该快速浏览所有PHP文件,重点关注以下几个部分:
- 包含用户输入的函数:如
$_GET、$_POST、$_REQUEST、$_COOKIE。 - 文件操作函数:如
include、require、file_get_contents、system、exec、passthru。 - 数据库操作函数:如
mysqli_query, 注意SQL语句的拼接方式。 - 任何自定义的过滤函数或正则表达式。
3. 核心漏洞审计:从代码到利用链
3.1 入口点分析与参数可控性判断
通过快速审计,我们锁定了一个关键文件——index.php。其核心代码简化后如下:
<?php highlight_file(__FILE__); $file = $_GET['file']; if(isset($file)){ if (strpos($file, “..”) !== false || strpos($file, “tp”) !== false || strpos($file, “input”) !== false || strpos($file, “data”) !== false){ die(“Hacker!”); } include($file); } else { include(“home.php”); } ?>这是一段非常典型的、存在漏洞的代码。它通过GET参数file接收一个文件名,然后使用include()函数将其包含进来。include()在PHP中不仅能够包含本地文件,如果配置不当(allow_url_include=On),还能包含远程文件,从而导致严重的安全问题。
代码中虽然有一个简单的黑名单过滤:
- 过滤了
..(目录遍历) - 过滤了
tp - 过滤了
input - 过滤了
data
但这个过滤是极其脆弱和不完整的。它只使用了strpos()进行字符串匹配,且是黑名单机制。我们的目标很明确:绕过过滤,让include()函数执行我们想要的代码。
3.2 过滤绕过与伪协议利用
首先,过滤..是为了防止目录遍历攻击(如../../../etc/passwd)。过滤tp很可能是想防止php://伪协议,过滤input和data则是为了防止php://input和data://伪协议。然而,这里的绕过方式非常多。
1. 大小写绕过:strpos()是大小写敏感的。PHP://或PhP://就可以轻松绕过对tp的检查。2. 嵌套协议绕过:PHP的流包装器支持嵌套。我们可以使用compress.zlib://php://input这样的形式。虽然php://被禁,但外层的compress.zlib://没有被禁,它内部依然可以封装一个php://input流。3. 编码绕过:使用URL编码。例如,php://编码后是%70%68%70%3a%2f%2f,strpos()在原始参数中找不到明文tp,同样可以绕过。
在这道题中,经过测试,最简单有效的方法是大小写绕过。我们尝试使用PHP://input作为file参数的值。php://input是一个只读流,可以访问请求的原始数据。这意味着我们可以在POST请求体中直接发送PHP代码,include()会将其当作PHP文件来执行。
3.3 构造利用链实现命令执行
现在,我们有了执行任意PHP代码的能力。下一步的目标是:在服务器上执行系统命令,从而读取flag文件。flag在CTF中通常位于根目录(/flag)、当前目录(./flag)或一个具有固定名称的文件中。
我们构造如下请求:
- 请求方法:POST
- URL:
http://target_ip:port/index.php?file=PHP://input(注意大写PHP) - 请求体(Body):
<?php system(‘ls /’); ?>
这个请求的含义是:告诉服务器,我要包含PHP://input这个“文件”,而这个“文件”的内容就是POST Body里的<?php system(‘ls /’); ?>。服务器端的include()会执行这段代码,调用system(‘ls /’)命令,列出根目录下的文件。
如果请求成功,我们会在页面返回中看到根目录的文件列表,其中很可能包含一个名为flag、flag.txt或flag.php的文件。假设我们看到了/flag。
接下来,我们修改请求体,读取这个文件:请求体(Body):<?php system(‘cat /flag’); ?>或<?php echo file_get_contents(‘/flag’); ?>
发送请求后,页面应该会直接输出flag的内容。至此,整个攻击链就完成了:信息收集发现源码 -> 代码审计发现文件包含漏洞 -> 大小写绕过黑名单过滤 -> 利用php://input伪协议执行任意代码 -> 通过system函数执行命令读取flag。
4. 深度拆解:漏洞原理与加固方案
4.1 文件包含漏洞详解与变种
这道题的核心是“本地文件包含”(LFI)漏洞,并通过伪协议升级为了“远程文件包含”(RFI)的效果。我们来深入拆解一下:
include()与require()的危险性:这两个函数的本意是用于代码模块化。但当其参数完全或部分由用户控制时,就极其危险。攻击者可以包含系统敏感文件(如/etc/passwd),包含日志文件(可能写入Webshell),或者如本题所示,包含伪协议来执行代码。- 伪协议是“魔法开关”:PHP内置的众多伪协议(
php://,data://,zip://,phar://等)极大地扩展了文件包含漏洞的利用面。php://filter可以用于读取文件源码(例如php://filter/convert.base64-encode/resource=index.php),php://input和data://则可以直接执行代码。 - 黑名单过滤的弊端:本题的过滤是典型的“无效黑名单”。安全领域有一条铁律:“黑名单永远会漏,白名单才是王道”。试图过滤掉所有危险字符是不现实的,总会存在绕过方法(大小写、编码、嵌套、冷门协议)。正确的做法是采用白名单机制,只允许包含预定义的、安全的文件。例如:
$allowed_files = [‘home.php’, ‘news.php’, ‘about.php’]; $file = $_GET[‘file’]; if(in_array($file, $allowed_files)){ include($file); } else { include(‘home.php’); }
4.2 从漏洞利用看安全开发要点
通过这道题,我们可以总结出几个对开发者至关重要的安全要点:
- 永远不要信任用户输入:所有来自外部的参数(GET, POST, COOKIE, Header)都必须视为不可信的。在将其用于敏感操作(包含文件、执行命令、查询数据库)前,必须进行严格的验证和过滤。
- 使用白名单而非黑名单:对于文件包含、文件上传、重定向等功能,尽可能定义明确的、范围有限的允许值列表(白名单)。
- 最小权限原则:运行Web服务的进程(如www-data用户)应该只拥有完成其功能所必需的最小权限。这样即使被攻破,攻击者能做的事情也非常有限。本题中,如果能限制Web用户对
/flag文件的读取权限,攻击链也会中断。 - 关闭危险配置:在生产环境中,务必在
php.ini中关闭allow_url_fopen和allow_url_include。这能从根本上杜绝利用伪协议进行远程文件包含和代码执行。
5. 实战演练与技巧延伸
5.1 手工利用与工具辅助的平衡
在CTF比赛中,熟练掌握手工利用技巧至关重要,它能帮助你理解漏洞的本质。就像这道题,你需要手动构造HTTP请求。我推荐使用Burp Suite的Repeater模块,或者命令行工具curl。
使用curl完成本题利用的命令示例:
# 第一步:探测是否可执行命令,查看根目录 curl -X POST http://target_ip:port/index.php?file=PHP://input --data “<?php system(‘ls /’); ?>” # 第二步:读取flag文件 curl -X POST http://target_ip:port/index.php?file=PHP://input --data “<?php system(‘cat /flag’); ?>”同时,也要善用工具。例如,在信息收集阶段,dirsearch能帮你快速发现robots.txt和source.zip;在代码审计时,可以使用grep命令快速搜索危险函数:grep -r “include\|require\|system\|exec” ./source_code/。
5.2 常见变形与赛题预测
这道题的模式非常常见,出题人可能会在以下几个方面进行变形,制造新的挑战:
- 过滤加强:过滤了“php”字符串,甚至使用正则表达式进行更严格的匹配。这时可能需要考虑使用其他伪协议,如
data://text/plain,<?php system(‘ls’);?>或利用zip://、phar://协议包含恶意压缩包。 - 无源码泄露:题目不提供
source.zip,需要你通过其他方式获取源码,比如利用php://filter读取index.php本身的源码:?file=php://filter/convert.base64-encode/resource=index.php,然后将返回的base64编码解码。 - 组合漏洞:文件包含漏洞可能需要结合其他漏洞才能利用。例如,先通过一个SQL注入将PHP代码写入日志文件,然后通过文件包含漏洞去包含这个日志文件。
- 限制命令执行:
system、exec等函数被禁用。这时需要思考PHP中还有哪些可以执行代码或读写文件的函数,如shell_exec()、passthru()、popen()、proc_open(),或者使用反引号`ls`。如果全部禁用,或许可以考虑用file_put_contents()写入一个Webshell。
5.3 赛后复盘与技能提升路径
解完一道题,千万不要就此结束。有效的复盘能让你收获翻倍:
- 搭建复现环境:在本地虚拟机(如使用Docker快速搭建LAMP/LEMP环境)中,完全还原这道题的代码和环境。亲手触发漏洞,观察每一步的结果。这是加深理解的最佳方式。
- 尝试多种解法:不要满足于一种payload。尝试用大小写、编码、嵌套协议等多种方式绕过过滤。思考如果过滤规则变化,你的绕过方法是否依然有效。
- 查阅官方文档:去PHP官网仔细阅读
include、require以及各个伪协议的文档。理解它们的设计初衷、参数和限制,你会在字里行间发现更多利用可能性。 - 关联知识体系:将文件包含漏洞放入整个Web安全知识体系中。它与文件上传、代码执行、日志注入等漏洞有何关联?如何形成组合拳?推荐阅读《白帽子讲Web安全》等经典书籍,并配合在
HackTheBox、TryHackMe或国内的一些合法靶场平台进行持续性练习。
这道2022年的国赛题,像一块棱镜,折射出Web安全基础中多个重要的知识点。它考察的不仅仅是某个漏洞的利用,更是选手在面对一个黑盒系统时,如何进行系统性的信息收集、逻辑推理和链条构建。对于中职乃至高职的网络安全学习者来说,把这类基础题吃透、嚼烂,建立起稳固的知识框架和实战思维,远比盲目刷题更重要。安全之路,始于足下,重在基础。希望这次的解析,能为你点亮一盏前行的灯。