这是我在 ctfshow 刷 Web 入门题的第四天。前三天里我靠 View-Source 和浏览器开发者工具就能把 flag 一个个翻出来到了 Day4 的 web3 和 web4画风突然变了页面不再把答案藏在注释里而是开始刁难“你是否来自本机”“你是否从站内页面跳转过来”。也就是说从这一题开始新手不得不正式接触 HTTP 请求报文学习用抓包工具改写请求头去和服务器“讲条件”。这篇文章把 Day4 的完整过程记下来。内容包括web3/web4 两道题目的解题思路、Burp Suite 抓包环境如何从零配好、X-Forwarded-For 与 User-Agent/Referer 这些请求头的具体作用以及一个新手在改包时最容易踩的几个坑。如果你是刚接触 Web 安全、准备系统刷 ctfshow 的新人这篇笔记可以直接照着操作省掉我摸索浪费的那几个小时。1. 开始之前Day4 的学习目标与题目定位1.1 从 web1 到 web4我卡在哪一课前两题本质上考的是“信息获取习惯”。web1 把 flag 写进 HTML 注释web2 把它藏到 JS 文件或开发者工具能看到的隐藏元素里。到了 web3页面源码干干净净注释里什么都没有一眼扫过去就是个很普通的欢迎页。如果还用老方法会一直卡在原地。真正让我停下来的是 web4。它不只是“看看源码”还需要主动去访问旁路路径并且要带着伪造的请求来源去访问。也就是说从 web3 开始解题模型从“观察”变成“交互”你得先猜服务器在用什么方式验证你再想方设法把你的请求改造成它期望的样子。这个过程非常像真实开发中的鉴权逻辑只不过 CTF 题把这些逻辑放大成了脑洞。1.2 新手最容易忽略的一件事先看提示再动手刷题时我养成了一个坏习惯拿到一个页面就急着乱点、乱试命令。web3 教我的第一课就是——题面提示本身就是线索。web3 页面上写着一句很直白的话“只允许本机访问你不是本机用户。”这句话乍一看像句废话其实翻译一下就是服务器在判断“谁在访问它”而且判断依据不是密码、不是 cookie而是 HTTP 请求头里的某个来源标识。web4 也一样页面给出“后台入口藏在 robots.txt 里”的暗示提示往信息收集方向走。如果忽略提示纯粹暴力乱试既浪费时间也练不出系统化思路。所以我把 Day4 的解题流程固定成四步读题面把关键限制条件圈出来用浏览器开发者工具看源码、网络请求、Cookie 等信息如果不行立刻交给抓包工具分析请求头按服务器可能采用的校验逻辑逐步修改请求并观察响应差异。这套流程到现在仍在用对学习任何 Web 方向的题目都适用。2. 环境准备半小时搭好可复现的抓包环境2.1 工具清单不装全家桶只装够用的Day4 开始前我确认了手头工具其实就三样Chrome 或 Firefox 浏览器抓包软件 Burp Suite Community 版免费版足够做新手题一个能看本地进程占用的小工具方便排查代理端口冲突。有读者可能问只用浏览器开发者工具的 Network 面板行不行我的答案是看静态请求可以改请求不行。web3/web4 这类题要求“在发送前改头、重放请求”开发者工具里的 Network 面板能看不能改改请求必须靠抓包软件或脚本。Burp 的 Community 版本安装也简单官网下载、保持默认下一步即可不需要额外配置 Java 环境因为新版自带运行环境。2.2 Burp 与浏览器关联的配置步骤配置 Burp 代理时最容易出问题的是“浏览器开了代理但证书没装”。完整顺序应该是打开 Burp进入 Proxy 模块确认监听地址是127.0.0.1:8080在浏览器里安装代理插件或手动设置系统代理HTTP 和 HTTPS 都指向127.0.0.1:8080浏览器访问http://burp下载 CA 证书导入到系统“受信任的根证书颁发机构”重启浏览器再访问任意 HTTP 站点Burp 里应该能看到完整请求。第 3 步经常被忽略。如果不装证书访问 HTTPS 页面会直接报证书错误请求根本发不出去。第一次配的时候我在这一步卡了 20 分钟后来文档里看到“导入证书后要重启浏览器”才解决。2.3 用一个简单页面验证环境是否通很多教程直接让人去 ctfshow 做题验证环境我建议别这么干——题目环境本身可能不稳定会干扰判断。我习惯先访问一个没有任何保护的目标比如本地起的测试页或浏览器默认安全页面观察 Burp 的 HTTP history 里是否出现完整的请求行如GET / HTTP/1.1请求头里的 Host、User-Agent、Accept 等字段响应状态码与响应体。只要这三点都出现说明抓包链路已经打通。之后再切到 ctfshow在 HTTP History 里选中目标域名的记录右键发送到 Repeater就能开始改包测试了。3. web3 实操当服务器要求“只能本机访问”时怎么办3.1 题目现象与判断思路打开 reveal 的 web3 页面正常访问时服务器返回一串提示意思是你不是本机用户拒绝给 flag。我当时的第一个想法是服务器是怎么知道我不是本机的Web 服务在没有 HTTPS 客户端证书的情况下最常用的判断方式有几种通过 TCP 连接的源 IP 判断也就是服务器直接从 socket 拿到的REMOTE_ADDR通过 HTTP 请求头里某个 IP 字段判断比如X-Forwarded-For、X-Real-IP、Client-IP通过 Host 头判断但这更偏向站点归属不是“本机”判断。如果服务器用的是第一种方式我远程访问根本无法伪造 TCP 源 IP题目基本无解。所以这种新手题更可能用的是第二种方式——直接信任客户端传上来的请求头字段。于是解题思路就变成从抓包里找到这个字段把它的值改成127.0.0.1再重放一次。3.2 在 Burp 中完成“改 IP”的完整操作我用 Burp 抓到了访问 web3 页面的请求包具体请求大致长这样GET / HTTP/1.1 Host: xxxxx.ctf.show User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Accept: text/html,application/xhtmlxml Accept-Encoding: gzip, deflate Connection: close请求头里没有 X-Forwarded-For。这很正常因为浏览器直连服务器时不会主动加这个头。我直接在 Repeater 的请求头区域手动加一行X-Forwarded-For: 127.0.0.1然后点 Send响应体居然真的变了flag 直接出现在页面上。不要小看这一步。很多人第一次改包会犯一个低级错误在请求头之间隔了空行或者字段名写错。HTTP 协议里请求头和请求体之间必须有一个空行如果你把新头插到空行下面服务器会把它当成请求体的一部分而不是请求头。改完务必检查格式保证新增的头和原有请求头连成一块。3.3 为什么服务端会傻傻地信任请求头拿到 flag 后我回过头查资料才发现这类校验在真实项目里也经常出现只不过“信任 XFF”是一个经典的安全误区。X-Forwarded-For 本意是给反向代理和负载均衡用的用户请求先经过 CDN 或 Nginx后端直接看到的 IP 是代理的 IP于是代理在转发时把这个头附上写上“原始客户端 IP”后端拿它做日志分析或限流。问题在于如果代理没有强制覆盖这个头用户完全可以自己伪造。比如我直接通过浏览器请求到源站请求头里自己写一个X-Forwarded-For: 8.8.8.8后端一读取就以为用户来自 8.8.8.8。CTF 出题人正是利用这个逻辑设计出一个“只允许本机访问”的场景考验新手是否知道请求头可以人为构造。新手经常混淆另外两个字段X-Real-IP和Client-IP。它们与 XFF 作用类似都是某种“客户端真实 IP”的替代方案。真实题目里服务器不一定只认 XFF可能还检查这些字段所以改包时可以依次尝试甚至几个一起加。我在 web3 里只加 XFF 就通了但到后面的便签题、SSRF 题里经常需要组合使用。3.4 这一题必须理解的三个细节看完答案只是入门真正吃透 web3 还需要知道三件事。第一不要急着改包先看服务器到底信任哪个字段。可以用“差量实验”分别只加X-Forwarded-For: 127.0.0.1、只加X-Real-IP: 127.0.0.1、同时加三个字段观察哪个响应有变化。这个思路比瞎猜高效得多。第二注意某些后端会把 XFF 当作“一串 IP 列表”来解析。例如X-Forwarded-For: 8.8.8.8, 127.0.0.1有的代码只取第一个有的取最后一个有的取正则匹配到127开头那句。如果只写一个值不成功可以试试把两个值倒序写或者写成127.0.0.1, 127.0.0.1。第三请求头字段名大小写不影响接收HTTP 规范里请求头不区分大小写但也有个别代码写成大写或小写才有反应。出现“改了没用”时优先检查拼写而不是怀疑工具坏了。我把这类要点整理成了一个小对照放在后文“踩坑实录”里。4. web4 实操Robots 协议隐藏入口与请求来源伪造4.1 第一反应看源码、找路径、别爆破web4 的页面打开后正文只有一句提示大意是欢迎来到站点但管理后台不在首页。源码里没直接注释 flag倒是有一个不太起眼的线索链接。我这时候学了乖先用开发者工具把页面里面所有script、a、img标签的地址过了一遍没有明显收获。然后想起 web3 的教训题目让你找“后台入口”那就应该访问一个和站点同域名的敏感路径。新手最容易在这里犹豫“该猜哪个目录”。其实不用猜先用 robots.txt 协议问一下站点自己愿意暴露什么。在地址栏直接访问http://目标域名/robots.txt返回内容很简单User-agent: * Disallow: /admin这意味着搜索引擎爬虫不应抓取/admin路径。对解题者来说Disallow 里列出的路径值得手动访问试试。我访问/admin后页面返回你不是管理员账号也不是从站内来源过来的请求禁止访问。4.2 拆解两个校验点UA 身份与 Referer 来源/admin的拒绝信息透露了两个关键信息它既检查客户端标识又检查请求来源。“不是管理员账号”通常对应两个方向登录 Cookie 或 User-Agent。web4 的页面上没有任何登录入口所以更可能是后者的简单字符串判断。我经验是新手题里常见两种写法一种要求 User-Agent 字符串里带admin另一种直接要求是某个特定 UA比如/Admin-Browser/1.0或admin。“不是从站内来源过来的请求”对应 HTTP 头里的Referer字段。Referer 是浏览器发送的“我来自哪个页面”的标识。很多后端会检查这个字段判断请求是不是用户在站内正常跳转产生的。真实场景里这叫防盗链或防跨站请求伪造CTF 里就简单粗暴地变成“Referer 必须等于站内地址”。于是我做了两手准备先用 Burp 抓/admin的请求包然后在请求头里加两行User-Agent: admin Referer: http://目标域名/发送后响应体变化了但返回的仍是一段提示大意是“后台登录少了关键头”。我继续补招把上一题学到的 IP 伪造也顺手加上X-Forwarded-For: 127.0.0.1再发送一次flag 就在响应体里出现了。总结下来web4 这题其实是 web3 的进阶版从“单个头校验”变成“多个头组合校验”但验证思路完全是同一套——读提示猜校验点逐项构造请求头。4.3 理解 Referer 校验与防盗链逻辑就算不在 ctfshow 刷题Referer 也是经常打照面的老朋友。下载站判断图片能不能外链视频站判断请求是不是从自己的页面点出来的都会依赖它。后端拿到请求头以后可能会执行以下判断判断 Referer 值是否以目标站点域名开头判断 Referer 是否为空判断 Referer 是否包含特定关键词。这种校验有一个常见弱点它信任客户端提交的头。既然 Referer 最终是浏览器生成的文本抓包工具就完全可以改成任意值。真实业务里仅靠 Referer 做安全防护并不充分所以各大厂商还会叠加签名、Token 之类的机制。CTF 题只考它的原因是帮助新手建立“HTTP 请求所有字段都可控”的基本认知。4.4 用 Python 脚本代替手工重放Burp 适合逐包分析但在验证“多个头组合的排列组合”时手工一个一个试太累了。这时候写个小脚本最舒服。我给 web4 写过一个很简短的验证脚本import requests url http://目标域名/admin headers { User-Agent: admin, Referer: http://目标域名/, X-Forwarded-For: 127.0.0.1 } resp requests.get(url, headersheaders, timeout10) print(resp.status_code) print(resp.text)每次改一个 header 的值运行一次比较响应体的差异很快就能锁定到底是哪个字段生效。注意这只是给合法 CTF 靶场环境使用真实互联网环境下不要拿这套逻辑去探测别人系统合规边界还是要守住。5. 踩坑实录新手第 4 天最容易翻车的 5 个地方5.1 抓包工具没开代理Burp 里一片空白我第一天配好 Burp 以后第二天打开发现 HTTP History 里什么请求都没有。最初怀疑软件坏了后来发现是被测浏览器没走代理端口。Windows 系统里打开“Internet 选项 - 局域网设置”把代理服务器地址和端口填对再访问页面Burp 立刻就有流量。使用代理插件时也要检查当前代理模式是否为“系统代理”或“全局模式”不能是“直连”。表格里补一条快速自查现象可能原因快速处理Burp 接收不到任何请求浏览器代理未指向 127.0.0.1:8080重新配置系统代理或浏览器插件HTTPS 页面打不开未安装 Burp CA 证书访问 http://burp 下载并导入根证书Repeater 发送无响应目标环境断网或地址失效回到浏览器确认原页面还能打开5.2 修改完请求头忘了发送或者在响应上找答案听上去很蠢但我真做过。在 Repeater 里改完请求头盯着响应文本框等了几秒以为是页面没回显其实是忘了点 Send。如果改了多次没有反应再检查一下当前是否选中了目标请求Repeater 的 Request 面板和 Response 面板是不是对应同一条记录。5.3 字段名写错、IP 值写错导致“伪造失败”XFF 的常见错法是把X-Forwarded-For写成X-FORWARDED-FOR、XFF或者把127.0.0.1写成localhost。虽然 HTTP 头字段名不区分大小写但拼写不能错。另外有些后端代码不仅检查 XFF还检查X-Real-IP、Client-IP单独改一个字段无效时不要气馁把另外两个也轮番加上。5.4 被 HTTPS 证书警告劝退新手很容易在证书报错这一步放弃。看到浏览器提示“您的连接不是私密连接”就停手殊不知抓包就是要安装并信任 Burp 的 CA 证书。把证书导入受信任根证书机构后HTTPS 请求就能正常抓到并转发。还有一点导入证书后某些浏览器需要重启进程不重启的话证书状态不生效。5.5 不比较响应差异纯粹乱试改包测试最忌讳的是“一次发送后只看响应里有没有 flag”。正确做法是每次只改一个变量然后保存下响应头、状态码、响应体片段和上一次对比。我用一个最简单的方式记录把每一次尝试的响应第一行复制到记事本里标注“加了什么头”。这样能快速发现规律也容易复盘。盲目批量测试只会把线索弄丢。6. Day4 之外的延伸请求头题目在真实环境里的投影6.1 为什么网络安全入门题都爱考请求头很多人会觉得“改个请求头就能拿 flag”太简单怀疑它价值不大。其实这类题背后是真实开发里的信任边界问题。一个请求从用户的浏览器发出路径上的任何一跳CDN、代理、反向代理都可能改写或增加头字段。后端的很多操作比如记录访问者 IP、判断是否来自站内、判断客户端环境都会依赖这些头。如果开发图省事直接信任客户端过来的头就会出现“改个 XFF 就能伪装本机访问”的漏洞。学习 Day4 的意义不只是会做题。它让我第一次意识到HTTP 请求就是一场“自报家门”的交流服务器判断你用什么身份完全依赖你自己怎么报。你把身份说成本机它就当真。这个认知对后面学习会话伪造、越权访问、CSRF 都有帮助。6.2 后续会碰到的同类考点注入、SSRF 与畸形文件在 ctfshow 的 web 入门路线里web3/web4 只是头部门槛。往后你会碰到更难的组合题很多热词里的方向我再点一句联合查询注入本质是让后端拼接 SQL 时把你构造的查询片段也拼进去需要熟练理解数据库查询语法与字段数探测SSRF服务器会根据 URL 参数去请求一个地址攻击面在于能否让它请求到内网地址一句话木马变形菜狗杯这类趣味赛里常见考察对 WebShell 特征的理解和对检测规则的绕过思路。这些方向虽然名词不一样但解题第一步都是“看懂请求与服务端处理逻辑”和 Day4 建立的思路一脉相承。我也是在刷完请求头题目后才不再对上面这些词汇发怵至少知道它们和 HTTP 报文息息相关。6.3 一点个人体会工具是死的思路是活的Day4 那天我最大的收获不是记住两个题解而是把“信息收集 - 假设校验逻辑 - 构造请求 - 对比响应”这个循环练熟了。第一次拿到 flag 时很兴奋但回头复盘发现大多数时间其实花在环境配置和字段名纠错上。如果早点学会用脚本批量试头还能节省不少时间。最后分享一个小习惯每做完一题我会把“服务器提示原文”和“最终生效的请求头组合”抄在一个 Markdown 笔记里标注清楚哪些字段是核心变量。刷到 Day4 之后这个笔记越来越厚回头看才发现它才是我真正的武器库。如果你也刚开始刷 ctfshow不妨从今天起一起保持这个记录习惯坚持到 Day30 再回看一定会有惊喜。