说实话,最初刷攻防世界的时候,我对这道 ics-06 的印象就是“页面好朴素”。没有登录框、没有上传点、没有搜索栏,一眼望去就是个工业控制系统的查询页面,放在那里像个铁疙瘩,不知道从哪下手。可恰恰是这种“看起来什么都没有”的题目,最能锻炼 Web 入门阶段的侦察思路。后来我顺着请求包摸到参数、挨个枚举、看到响应长度突变的那一刻,才明白这题为什么被归为入门必刷——它不考花哨的漏洞利用,考的就是你愿不愿意踏踏实实把流量看清楚。
这道题适合刚接触 CTF Web、会开 Burp Suite 但还没独立打通几道题的新手,也适合想复习“参数枚举”和“越权数据获取”这类基础手法的老手。整道题流程很短,但里面涉及的工具配置、爆破策略、响应判断,都是之后打别的题天天要用的基本功。下面我把完整过程、背后的判断逻辑,以及我踩过的坑一起写出来。
1. 题目分析与环境准备
1.1 先认清楚这道题到底在考什么
ics-06 的题目场景是“工控云管理系统”,打开之后是一个设备维护相关的页面。CTF 里凡是带 ics 前缀的题,一般会往工业控制系统、SCADA、设备管理平台这些方向靠,但入门题基本不会真让你去分析 Modbus 协议或 PLC 寄存器,它只是借了一个工控场景的壳,考的依然是 Web 层的东西。
这道题的核心考点有两个:
- 参数发现:页面某个功能会把请求参数传到后端,但参数不会大张旗鼓地写在页面上,需要你通过抓包或观察 URL 变化来找。
- 越权数据获取:后端在查询数据时没有做好权限校验,遍历参数值就能拿到不属于当前会话的数据,flag 就藏在其中某一条记录里。
很多新手看到“工控”两个字就慌,觉得要会硬件知识、要懂组态软件。不用。你把它当成一个普通的查询页面就行,场景只是外衣,参数才是内核。
1.2 工具准备与代理配置
打这道题我用的工具很常规:
| 工具 | 作用 | 备注 |
|---|---|---|
| 浏览器 | 访问题目、观察页面行为 | Chrome/Firefox 都行 |
| Burp Suite Community | 抓包、改包、爆破参数 | 社区版够用 |
| FoxyProxy 或手动代理插件 | 把浏览器流量代理到 Burp | 也可以用 Burp 内置浏览器 |
Burp Suite 的代理配置这里多提一句。默认监听地址是 127.0.0.1:8080,浏览器代理设置为 HTTP 代理指向这个地址就行。如果你用的是 Burp 自带的浏览器,它会自动走代理,省去配置的麻烦;如果你习惯用自己常用的浏览器,记得装一个代理切换插件,避免“抓不到包”或者“开了代理连不上网”的尴尬。
环境配好之后,先访问题目页面,随便点一点,确认 Burp 能正常抓到 HTTP 请求,再开始正式分析。这一步不能省,工具没打通,后面全是白费。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 初步侦察:发现功能点与关键参数
2.1 页面浏览与功能点记录
我第一次打开题目时,页面上就是一个类似“设备维护中心”的界面,旁边有入口链接,点进去之后会看到一个设备查询的页面框架,表面上只有一个按钮或报表区域,没有任何输入框。这时候别急着关页面,先做三件事:
- 把页面上的所有文字、按钮、链接挨个点一遍,看 URL 有没有变化。
- 打开浏览器的开发者工具(F12),切到 Network 标签,刷新页面,看加载了哪些资源。
- 把每个请求都发到 Burp 的 HTTP History 里,看完整的请求路径和参数。
我当时点了一个类似“查询”按钮后,发现浏览器地址栏跳成了一个带参数的 URL,大概是 /index.php?id=1 这种格式。这就是整道题最关键的信息——后端接口接收了一个名为 id 的参数,并且把值传进了查询逻辑。
这里要强调的是,很多人会忽略页面本身给的信息,直接拿扫描器去扫目录。对于入门题,页面上这个带参数的请求就是最明显的入口,拿到它,题就做完了一半。
2.2 抓包确认请求结构
用 Burp 抓到点击查询时的完整请求包,大概是下面这个样子:
http复制GET /index.php?id=1 HTTP/1.1
Host: 61.147.171.105:xxxxx
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.7,en;q=0.6
Connection: close
没有 Cookie、没有 POST 数据、没有额外的 Header,干净得像一张白纸。这意味着服务端对请求的唯一身份区分就是 id 这个参数。把 id 从 1 改成 2,响应内容大概率会有细微变化,比如设备 ID、设备名称、状态字段。这时候基本可以确定,后端是在根据 id 从数据库或配置表里查记录,而且没有带任何权限校验。
有的版本题目里参数名可能不是 id,可能是 query、content_id、cid 之类的名字。不用纠结具体叫什么,核心思路一致:找到那个改变响应内容的参数,然后穷举它的取值。
2.3 手动测试与响应差异对比
在爆破之前,先手动测几个值,感受一下响应规律。比如:
id=1:返回设备 A 信息id=2:返回设备 B 信息id=9999:返回空或报错
手动测试的意义在于建立“正常响应”和“异常响应”的基线。你后面用 Burp Intruder 爆破时,需要知道什么样的响应长度是正常的、什么样的响应长度意味着可能命中了目标。如果一上来就盲目爆破,面对一堆结果根本分不清哪个是我们要的。
另外,手动测试时注意观察响应包的 Content-Length。有时候响应的内容变长,不一定是因为有 flag,可能是因为输出了错误堆栈。但有的时候 flag 就是藏在某个 id 值对应的正常查询结果里,你需要通过响应长度的差异把它挑出来。
3. 突破核心:参数枚举与越权数据获取
3.1 为什么选择枚举而不是注入
确定了 id 参数之后,很多新手会下意识想到 SQL 注入,试着在参数后面加单引号、and 1=1 之类的 payload。这题如果按注入的思路去测,大概率是无功而返,因为题目设计者想考察的就是纯粹的越权遍历:后端对参数值没有做访问控制,遍历参数就能访问到所有记录。
这里有个经验之谈:入门题先做“合法操作下的越权”,再做“非法构造的注入”。你把 id 从 1 遍历到几千,能拿到 flag 就说明是平行越权;如果你遍历完了还是一无所获,再考虑注入、文件包含、反序列化这些更复杂的攻击面。顺序反了的话,很容易在题目里钻牛角尖,浪费时间。
3.2 用 Burp Intruder 爆破 id 参数
把刚才抓到的请求包发送到 Burp Intruder(在 Burp 里右键请求,选择 Send to Intruder),然后按下面的步骤配置:
- Positions 标签页:把
id=1中的1选中,点击右侧的Add §,把它标记为爆破位置。请求会变成id=§1§。 - Payloads 标签页:Payload type 选择
Numbers,设置范围。常见范围是1到5000,步长1。2400 到 2500 间隔 1,以及几千上万的区间,通常都能覆盖。 - Resource Pool 或线程设置:社区版 Burp 的 Intruder 跑得比较慢,建议线程数不要开太高,默认或者 1 个线程都行,避免被限速或漏数据。攻击靶场时线程太高容易把靶机打崩,也容易触发风控。
- Options 标签页:勾选
Grep - Match,可以添加flag、ctf、{这些关键字,方便在结果里快速定位。也可以直接在响应中比对长度。
配置完成后点击 Start attack。爆破过程中,Burp 会按顺序发送请求并记录每个响应包的状态码、长度、耗时。大多数请求的响应长度是固定的,比如都是 2000 多字节,一旦某个请求的响应长度明显不一样,比如突然变成 5000 字节或者 300 字节,那基本就是中奖了。
3.3 命中点分析与 flag 获取
在我当时爆破的过程中,跑到某个 ID 时,响应长度突然出现了一个明显的峰值。点开那条记录,响应正文里直接出现了一行类似:
code复制flag{...}
的内容,前面的查询内容也跟其他设备记录完全不同。那一刻就知道,题目解完了。
这里有一个常见误区:有些新手会把响应长度差异当成唯一判断标准,结果把一堆报错页面当作目标,挨个看过去浪费时间。正确做法是同时关注长度、状态码和关键字命中,三者交叉验证。比如响应长度突变且状态码仍是 200,那大概率是正常业务数据;如果响应长度突变但状态码是 500,那可能是参数越界导致的异常,不是我们要的结果。
另外,拿到 flag 之后别急着走,回到 Burp 的 Repeater 里重新请求一次该 id,确认 flag 对应的响应是稳定的。有时候靶场环境有缓存,第二次请求可能返回空,但第一次的数据也足够证明你找到了正确答案。
3.4 为什么这个方法有效:理解越权漏洞的本质
把这个流程拆碎来看,本质上就是一句话:服务端没有校验“当前用户是否有权限访问 id=X 对应的资源”。设备查询接口从参数里拿到 id 后,直接拼到 SQL 或数据查询逻辑里,把查到的记录原样返回。
正常情况下,一个已登录运维用户只能查看自己负责的设备,但服务端没必要每个请求都校验一次用户身份与资源归属,这种信任一旦被突破,攻击者只要修改参数值,就能把别人的设备信息全部拉出来。CTF 里这种题目到处都是,真实业务里这类漏洞也屡见不鲜。
所以这题的意义不只是“拿到一个 flag”,而是让你建立一种直觉:凡是看到接口带着数字 ID 参数,脑子里要立刻跳出三个字:“能不能遍历?”
4. 常见问题与排查技巧实录
4.1 问题一:Burp 抓不到包
新手最常遇到的情况就是,浏览器能打开题目,但 Burp 的 HTTP History 里空空如也。排查思路:
- 检查 Burp Proxy 的
Intercept是否开启,以及监听端口是不是8080。 - 检查浏览器代理配置是否生效,访问
http://127.0.0.1:8080看是否能打开 Burp 的 CA 证书页面。 - 有些靶场是 HTTPS 或 WSS 协议,需要先安装 Burp 的 CA 证书,浏览器才会信任代理。
如果以上都没问题,直接换 Burp 内置浏览器打开题目,这是最省事的方式。
4.2 问题二:Intruder 爆破结果全都是 200,长度也没有差异
遇到这种情况,先回头看一下参数名是不是找错了。有的题目页面里可能同时存在好几个请求,你爆破的那个参数并不影响响应内容,真正的敏感参数藏在另一个 JS 文件或另一个接口里。建议把 HTTP History 里所有带参数的 GET/POST 请求都翻一遍,挑出响应体随参数变化的那一个。
还有一种情况是参数类型不是纯数字,可能是字符串。这时候用 Numbers payload 跑不出结果,应该换成 Simple list,自定义一堆可能的取值,或者用 Brute forcer 跑字母数字组合。入门题通常不会把参数搞得太复杂,但遇到“数字遍历无效”时,记得换个 payload 类型试试。
4.3 问题三:爆破速度太慢
Burp 社区版有 Intruder 的限速,跑几千个请求可能要等好几分钟。如果嫌慢,可以用 ffuf 或 wfuzz 这些命令行工具做相同的事,速度快很多。比如:
bash复制ffuf -u "http://target/index.php?id=FUZZ" -w <(seq 1 5000) -mc 200 -fs 正常长度
-fs 参数用来过滤掉正常响应长度,只显示长度不同的响应。不过考虑到这是入门题,用 Burp 慢慢跑也不算煎熬,毕竟我们同时还学到了怎么分析响应差异。
4.4 经验:拿到 flag 后的收尾习惯
攻防世界的题目,有些是提交 flag 后自动判定,有些需要你把 flag 复制到输入框里交卷。无论哪一种,建议先把 flag 全文复制到本地记事本,避免切换页面时丢内容。同时把关键流量包截图保存,写 writeup 或跟朋友交流时都用得上。这不算什么高深技巧,但关键时刻能省不少事。
5. 从这道题延伸出去的几个思考
5.1 越权漏洞在真实场景里的“升级版”
ics-06 里我们遍历 id 拿数据,这在真实业务里叫 IDOR(Insecure Direct Object Reference),即“不安全的直接对象引用”。真实系统里,这个 id 可能是订单号、用户编号、文件 ID、发票号码,甚至是一张 PDF 的下载路径。攻击者把 id 改一改,就能看到别人的订单、下载别人的文件、查询别人的个人信息。
真实场景里往往不会只有一个参数,可能有 user_id、order_id、file_id 等多个参数。判断越权漏洞,除了挨个枚举,还要观察响应里的数据是否包含敏感字段,比如手机号、身份证、内部 IP、数据库信息。CTF 里的 flag 就是“敏感字段”最简单的抽象,换到实战里,它可能就是千万条用户数据。
5.2 给新手的后续练习建议
刷完这道题,如果想趁热打铁,可以再去攻防世界找几道同类型的 Web 入门题练手,重点是练参数识别和响应对比这两个能力。具体建议:
- 再去刷两道带
id参数的题目,逼自己不借助 writeup 独立完成。 - 尝试用
ffuf替代 Burp 做一次爆破,感受命令行工具的效率和参数调优。 - 把这道题的完整过程写一篇自己的 writeup,哪怕只是备忘录,也能帮你梳理思路。
CTF 这东西,看十篇题解不如自己动手打通一道。ics-06 作为入门题,最大的价值就是让你快速经历一遍“发现问题参数 → 构造枚举 → 对比响应 → 拿到结果”的完整闭环。后面再遇到类似的题目,你会条件反射一样打开 Burp,先把参数找出来,再想下一步。
最后再分享一个小技巧:打通一道题之后,别急着删靶机环境或关页面,用 Burp 的 Repeater 把几个关键参数再多测一遍,比如把 id 改成负数、改成超大数、改成字符串,看看响应的变化。这种“答题之外的胡闹”,往往能让你对后端逻辑的理解深一层。很多入门选手缺的不是做题数量,而是这种主动探索的意识。
