CTF-SHOW 的 WEB 系列,尤其是最前面的这 9 道题,是我见过最典型的 Web 安全入门训练。它们不追求把题出得多难,而是逼着你去把“网页到底是怎么跑起来的”这个问题彻底搞明白。很多人刷完这一阶段再回头看,会发现自己的信息收集习惯、HTTP 请求构造能力、源码分析思路和参数类型敏感度,都在不知不觉中打了一层底子。
这套题适合两类人:一类是刚接触 Web 安全、不知道从哪里下手的新手;另一类是自己写过不少接口,却从来没从攻击者视角看过自己代码的开发者。前者能靠它建立一套完整的排查思路,后者能靠它发现自己日常编码里最容易忽略的细节。我下面不打算按题号逐题报答案,而是把这个阶段背后的通用逻辑、工具配合方式和实操流程讲透。你拿着这套思路去刷其他入门平台,一样管用。
1. 这一阶段到底在练什么:从信息收集到请求伪造的认知升级
1.1 为什么叫“第一阶段”而不是“新手题”
很多人一看到“入门题”就觉得应该秒出答案,结果发现自己卡了一下午,于是开始怀疑智商。其实问题不在难度,而在规则不同。这 9 道题真正要训练的,不是某个高深漏洞的利用,而是三个在内部渗透测试和日常漏洞挖掘里天天都要用的底层习惯:
第一个习惯:拿到网页先看源码。 很多线索就藏在 HTML 注释、JS 文件或静态资源里,你看页面渲染结果永远看不到这些东西,因为它们不会出现在屏幕上,只会出现在源码里。
第二个习惯:每看到一个请求,先问它用的是什么方法、带了哪些头部。 一个请求由请求行、请求头和请求体组成,前端页面只是这些信息的可视化外壳。你要做的不是“点按钮”,而是“看请求”。
第三个习惯:页面没反应,先想是不是参数没对上。 后端拿到的参数名、参数类型、参数位置可能和你想象的不一样。前端能跑通,不代表你手搓的请求就能让后端认账。
这三个习惯看起来琐碎,但这就是 Web 安全测试里最核心的信息收集意识。题目“简单”,本质上是在帮你把流程练成肌肉记忆,而不是逼你背一堆花哨 payload。
1.2 前 9 题常见的考察点拆解
我从多套常见入门题里总结了一下,这个阶段大概会覆盖四个方向。不同平台的题目设定未必完全一致,但换汤不换药:
| 方向 | 典型表现 | 你要掌握的技能 |
|---|---|---|
| 前端与静态信息泄露 | HTML 注释藏线索、JS 文件里有提示、存在 robots.txt 或备份文件 | 对网页做最基础盘查,能用浏览器和命令行工具访问常见路径 |
| 请求方法与请求头控制 | 要求改用 POST、伪造来源地址、修改用户代理、篡改 Cookie | 完整理解 HTTP 请求结构,能手动构造任意请求 |
| 服务端参数处理 | PHP 弱类型比较、MD5 特例、参数类型混淆 | 知道字符串、数字、数组在服务端语言里的行为差异 |
| 简单注入探测 | SQL 注入的入门检测、基础过滤绕过 | 能判断参数是否进入查询逻辑,并做可验证的条件判断 |
这些知识点看着分散,实际是一条完整链路:前端信息收集 → 请求构造 → 参数分析 → 漏洞验证。从第 1 题到第 9 题的排列逻辑,基本就是在按这条链路递进。所以我一向建议别跳着刷,顺序本身就是教材。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工具链路:一条你可以闭眼复制的调试路线
2.1 浏览器开发者工具:第一案发现场
我见过不少人在题目页面里点来点去,却不知道按一下快捷键打开开发者工具。这非常可惜,因为很多题答案就藏在源码里,只是你没去看。浏览器开发者工具是最顺手的第一现场,你在“元素”面板能看到完整 HTML 源码,包括注释;“网络”面板会记录页面加载过程中的所有请求,包括每条请求的方法、状态码、响应大小和耗时;“存储”面板能看到 Cookie 和本地存储;“源代码”面板可以快速定位页面引入的所有脚本。
值得强调的一点是:很多网页在渲染后会被 JavaScript 动态改动,你直接看截图没有任何意义。正确做法是打开“元素”面板,看渲染完成后的真实 DOM 结构,尤其是 HTML 注释。注释里藏 flag 或者提示,是这个阶段最经典的操作,也是一道明晃晃的送分题,前提是你真的去看源码了。
在这个环节我还有一个习惯:先禁用浏览器脚本再重新加载页面。有些前端校验会在脚本里拦截操作,关掉脚本后,原本隐藏的按钮、表单甚至接口地址都会直接暴露。看源码不是“扫一眼”,而是从头到尾过一遍。
2.2 curl:最快的请求改造工具
浏览器适合观察,但说到“手动构造请求”,命令行工具才是改造效率最高的方式。不需要打开任何图形界面,一条命令就能把请求方法、UA、Referer、Cookie 全部改掉。下面几条命令是我平时使用频率最高的,你可以直接抄走:
bash复制# 查看完整请求与响应,包括响应头
curl -v http://challenge.local/
# 改用 POST 提交表单数据
curl -X POST http://challenge.local/login -d "username=admin&password=admin"
# 伪造用户代理和来源地址,同时携带 Cookie
curl -A "Mozilla/5.0" -H "Referer: http://challenge.local/" -b "admin=1" http://challenge.local/flag
这里有个很常见的新手误区:觉得只要有 -X POST 就一定能发 POST。其实 -d 参数会让 curl 自动切换为 POST 方法,所以很多场景直接写 -d 就够用了。另外,-v 是我最建议新手加上的参数,它会打印完整的请求头和响应头,你能清清楚楚看到自己到底发了个什么出去,排查问题时会省很多力气。
如果参数值里带了特殊字符,我一般建议用 --data-urlencode 而不是裸写 -d,它会把特殊字符做 URL 编码,避免服务端解析时断掉。
2.3 什么时候轮到图形化抓包工具登场
当请求变得复杂,或者你需要在同一个请求上反复修改时,命令行就不够高效了。这时候我会改用图形化抓包工具。工作流很简单:浏览器配置本地代理,把所有流量转发到抓包工具,然后在工具里拦截请求、修改内容、再放行。配置一次之后,所有请求都能随时停下来编辑,比每次重新拼 curl 命令舒服得多。
新手最容易犯的错误,是把抓包工具当成“记录器”:看一眼请求内容,然后回到浏览器里手动改。但工具最有价值的是“拦截并修改”能力:请求还没到达服务器之前,你可以任意改方法、改请求头、改请求体,改完再放行。这在使用场景上有本质区别。比如页面里有个输入框限制了只能写数字,前端校验做得再严,拦截工具里一样可以改成任意字符串再提交,因为后端收到的永远是原始请求。
我常用的工作流是“两步走”:第一步用浏览器开发者工具快速看请求结构,第二步把整个请求交给抓包工具做精细修改。这套配合下来,几乎能覆盖入门阶段 90% 的操作需求。
3. 一套能用在绝大多数题目上的实操流程
3.1 五步法:跑通一套题的通用节奏
刷题最忌讳拿到题就到处乱点。我给自己定的节奏是固定的五步,不管题难还是简单都按这个顺序走:
- 信息收集:打开页面,看完整源码,顺手访问 robots.txt 和常见备份路径,再用网络面板确认页面发出了哪些请求。这一步不追求找到答案,只追求“不遗漏线索”。
- 确定入口:找到表单参数、URL 参数、请求头、Cookie 中的至少一个可操作点,想清楚题目要我改哪个变量。
- 构造请求:一次只改一个点。改完立刻看响应是否变化,如果没变化,分析原因再改下一个。
- 判断响应差异:不要只看页面“长得不一样”,要看状态码、响应长度和关键字段的变化。flag 经常藏在响应头或者 302 跳转里,页面本身根本看不到。
- 复盘记录:用笔记记录每道题的入口点、我改了什么、响应发生了什么变化。这个习惯越到后面越值钱。
这套五步法的核心逻辑是“可对比、可复现”,而不是“碰运气”。你每一步都知道自己在做什么,出了问题也知道去查哪里。
3.2 用一个“静态泄露”场景走一遍流程
假设题目页面只有一个登录框,没有任何提示。按五步法走:先看源码,如果注释里出现类似 <!-- hint: check robots --> 的文字,说明入口指向了 robots.txt。用命令行工具访问:
bash复制curl http://challenge.local/robots.txt
如果返回内容里出现 Disallow: /flag.txt 这样的条目,再访问 /flag.txt,往往就能直接拿到结果。
这个过程看起来像抄近路,但背后的思路其实是“顺着提示做静态路径探测”。robots.txt、备份文件、.git 目录泄露,都是 Web 安全测试里非常经典的信息收集方向。很多新手会跳过这一步直接去想复杂的漏洞利用,结果绕了一大圈才发现入口就在眼皮底下。这也是为什么我坚持第一步必须是完整盘查源码与常见路径,而不是凭感觉猜。
3.3 用一个“PHP 弱类型”场景走一遍流程
假设题目给了这样一段核心代码:
php复制if ($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b'])) {
echo $flag;
}
这段逻辑的要求很明确:参数 a 和 b 的值不相等,但它们各自计算出来的 MD5 值在弱比较 == 下相等。很多新手第一反应是想找两个字符串,让它们的 MD5 都以 0e 开头,比如已知的 0e123 这类“魔数哈希”。但更通用的解法是借助 PHP 的数组参数行为:当 $_GET['a'] 传入数组时,md5() 函数会因为参数类型不匹配返回 NULL,两个 NULL 在弱比较下自然相等;而两个数组本身在 != 比较下并不相等。
请求这样构造:
bash复制curl "http://challenge.local/flag.php?a[]=1&b[]=2"
这一步的要点不是背诵 payload,而是理解服务端语言在类型处理上的特殊性。很多入门题就是在考你能不能突破“参数只可能是字符串”的思维定势。你把参数形式从字符串换成数组,后端的判断逻辑就可能完全变样。
3.4 用一个“SQL 注入探测”场景走一遍流程
当页面出现类似 ?id=1 的参数时,可以先做一个最基础的存在性判断。先正常访问 ?id=1,再看 ?id=1',比较两次响应的差异。如果报错形式不同,或者页面内容出现变化,说明这个参数大概率被拼进了 SQL 语句。
接下来可以用条件表达式验证。访问 ?id=1 and 1=1,再访问 ?id=1 and 1=2,对比两个响应。如果第一个返回正常内容、第二个返回异常或空白,就说明我们的条件确实影响了后端查询逻辑。这个“恒真与恒假对比”的方法,是一切 SQL 注入判断的地基。
我在练习时几乎不用自动化工具跑这一步,而是先手工把流程走完。原因很简单:能手工判断,说明你理解了注入的本质;一上来就挂工具,你只得到了一个结果,却丢了最重要的判断过程。
4. 常见卡点与问题排查技巧实录
4.1 新手最容易卡住的五个位置
我带人刷题时反复听到的问题,基本都集中在下面五个环节,你如果卡住了,按顺序排查就行。
第一,改了请求方式却没改参数格式。很多题要求从 GET 改成 POST,或者反过来。但你改了方法,却忘了把参数放到正确的位置,后端当然没有反应。
第二,只改了页面上的输入框,没改实际发出的请求。前端限制只能拦得住不熟悉工具的人,后端判断的是原始请求,所以必须在代理工具或命令行里直接改请求体才能生效。
第三,伪造请求头时被变量名迷惑。比如伪造来源地址,需要区分是 Referer 还是 X-Forwarded-For,不同题目读的字段可能完全不同。位置的差异不是玄学,就是测试点设置不同,只能靠抓包确认。
第四,编码和转义问题。参数值里带特殊字符时,必须做正确的 URL 编码。直接在浏览器地址栏手输内容经常会丢失部分符号,导致后端拿到不一样的参数。
第五,只看了页面渲染结果,没分析响应包。flag 可能藏在响应头、302 跳转后的 Location 字段,或者某个不起眼的字段差异里。只看视觉页面,往往什么都发现不了。
4.2 问题排查速查表
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| 页面空白但状态码 200 | 请求参数缺失或错误 | 用网络面板或命令行工具核对请求参数与题目提示 |
| 提示 method not allowed | 请求方法不匹配 | 依次尝试 GET、POST、HEAD、OPTIONS 等常用方法 |
| 修改请求头后仍然无效 | 头字段名或取值格式不对 | 打印完整请求头,逐字核对大小写和取值格式 |
| 页面内容完全没有变化 | 请求没到达目标接口 | 检查域名、路径大小写、末尾斜杠和端口号 |
| 响应内容与预期不一致 | 前端 JS 动态生成页面 | 禁用脚本刷新,或直接查看接口原始返回数据 |
| 本地测试正常但题目环境报错 | 本地与题目的 PHP 版本、函数行为不同 | 尽量在题目提供的环境中验证参数行为,避免依赖本地结论 |
这张表本质上就是“先确认请求本身,再确认服务端解析,最后确认响应展示”的排查顺序。顺着这个顺序走,大部分入门题的问题都能定位。
4.3 三个适合长期坚持的练习习惯
第 4 章的收尾,我想留下三条我从实践里总结出来的习惯,它们比任何一道题的答案都重要。
第一个习惯:永远用对比法看响应。每改一个参数,就要跟上一版请求的结果做比较。响应长度、状态码、关键字段只要有任何变化,都说明你的改动被后端接收到了。没有变化的修改,等于没做。
第二个习惯:坚持写打题笔记。每道题记三行内容:入口点是什么,我改了什么,响应发生了什么变化。这个习惯在入门阶段看不出差距,但刷到几十题之后,你会发现自己判断方向的速度明显比不记笔记的人快,因为你的错误模式已经被自己整理过一遍了。
第三个习惯:明确练习边界。所有攻击性验证都只在授权的靶场环境里进行,绝不拿真实系统练手。这不是场面话,而是做安全工作最基本的职业底线。你在这里学会的每一招,都应该用来保护系统,而不是破坏系统。把边界守好,你的路才能走稳。
