☰
pikachu靶场通关知识地图:从入口到执行的Web漏洞复习主线
2026/10/30 8:35:43 网站建设 项目流程

简介:《pikachu靶场全通关教程》面向刚接触网络安全渗透测试的学习者与课程实践者,围绕Pikachu靶场常见漏洞模块提供通关思路与练习复盘,帮助建立从漏洞识别、工具使用到结果验证的基础认知。资源包为1个PDF文件,约16.9MB,内容以图文笔记形式串联靶场关卡,便于按模块检索和对照学习。已有4825人学习,具备一定的参考与交流价值。教程覆盖暴力破解中的表单爆破、服务端与客户端验证码绕过、Token防爆破及Burp Suite宏与递归搜索等用法,也涉及反射型XSS的GET与POST场景,并记录破解过程、关键配置和排错思路。读者可借此熟悉渗透测试常用工具流程、理解漏洞成因与防护要点,并对照自身练习查漏补缺,适合作为入门阶段的靶场通关参考笔记。

1. pikachu 靶场通关的知识地图:从入口到执行的一条主线

pikachu 靶场通关的难点从来不在工具本身,而在于把几十个关卡看成一条线。我第一轮是一关一关照着做,做完就忘;后来把题目重排了一遍才发现,整套靶场沿着「拿到入口 → 让输入被执行 → 把执行变成文件与命令」这条主线铺开:暴力破解负责拿到入口,XSS 负责验证输入能不能变成浏览器里跑的代码,SQL 注入验证输入能不能变成数据库语句,RCE、文件包含与上传则把这条链路推到服务器上。线理顺了,每关考什么、下一关复用哪招,心里就有底。

这份笔记更适合当复习地图用,不是逐关截图。已经跟着教程打过一轮、但做题还要回头翻记录的人能对上号;刚学完基础、想知道这些关卡之间到底什么关系的人,也能先拿到骨架。下面按模块拆,每一节都落到考什么、怎么判断、哪一步最容易翻车。

2. 暴力破解四连:表单、验证码与 token 的破解节奏

2.1 三种攻击模式先分清:狙击、音叉、集合炸弹

同一套字典,选错攻击模式,结果会差很远。Intruder 的四种模式本质上是「payload 怎么组合」的区别,先把组合方式想明白,再去配字典,比背按钮位置有用得多。

模式组合方式典型场景请求总量
Sniper单字典轮流打在每一个位置上,其余位置保持原值只怀疑某一个字段字典长度 × 位置数
Battering ram所有位置用同一个 payload账号密码相同、或字段重名字典长度
Pitchfork多字典按索引一一对应,取最短已知用户名,只爆密码加 token 同步最短字典长度
Cluster bomb多字典笛卡尔积,全组合账号和密码都要枚举字典长度之积

表单爆破这一关,账号和密码都不确定,所以原文用的是集合炸弹。集合炸弹的请求量是乘积关系,几百乘几百就是几万请求,线程数和超时没调好很容易把服务端打崩或者把自己卡死。下面这段代码把组合逻辑写清楚了,理解它比记界面更重要:

# 集合炸弹的本质:两个位置各自独立取值,结果取笛卡尔积 users = ["admin", "test", "pikachu"] # 位置1(用户名)的可选集合 pwords = ["123456", "admin888", "p@ssw0rd"] # 位置2(密码)的可选集合 count = 0 for u in users: for p in pwords: count += 1 print(f"{u}:{p}") # 实际爆破时,这里换成一次登录请求 print("总请求数 =", count) # 3 x 3 = 9,字典再大一点就是乘法爆炸

对比一下音叉就能看出差别:音叉是索引对齐,两个字典第 n 项配第 n 项,长度取最短,用它去爆账号密码,字典长度不一致时会直接漏掉一半组合。至于结果判读,别只盯着响应长度,状态码、是否 302 跳转、跳转后页面里有没有出现用户名,三个信号一起看才可靠,只按长度排序是最常见的误判来源。

2.2 服务端验证码绕过:宏到底在替谁干活

服务端验证码这一关,很多人卡在「每次刷新都变,怎么爆」。把请求链路拆开就清楚了:验证码是服务端生成的,生成时就绑在当前会话上,前端只是把图片显示出来。也就是说,只要让工具在每次提交登录之前,先自动去要一张新验证码、把上面的值提取出来、再填进登录请求,这个循环就成立了。宏(Macros)干的就是这件事。

原文的配置顺序是:先抓登录包,用过滤器username:"admin",password:"123456"把目标请求筛出来;再到会话处理里添加宏,宏里放「获取验证码」的那个请求;接着添加自定义参数,把验证码响应里的值提取成变量,注意参数名称必须和登录请求里的字段名完全一致,对不上就替换不进去;最后设置宏的生效范围,把规则范围限定在登录表单提交的那个 URL 上。

用命令行复现一遍这两步,比在界面上点更直观:

# 第 1 步:请求验证码,同时把服务端下发的会话 Cookie 存下来 # -c 表示写入 cookie 文件,验证码和会话是绑定的,这步不能省 curl -s -c cookie.txt "http://target/vul/vulcode.php" -o code.png # 第 2 步:带着同一个 Cookie 提交登录 # 验证码字段填服务端刚生成的那个值,换会话就会提示验证码错误 curl -s -b cookie.txt \ -d "username=admin&password=123456&code=abcd" \ "http://target/vul/vulcode_login.php"

真正决定成败的是作用范围。宏的 scope 如果设成全站,每个静态资源请求都会触发一次取验证码,速度慢不说,还会不停刷新服务端会话,导致提交时验证码早就失效了。限定在登录提交请求上,才是「一次登录请求配一次取码请求」的正确节奏。

2.3 token 防爆破:宏和递归搜索两条路

token 关卡的原理和验证码接近,区别在于 token 藏在页面源码里,而不是图片里。原文给了两种打法,思路不同,适用条件也不同。

第一种还是宏:把「打开登录页」这个请求放进宏里,从响应正文中用正则把 token 提出来存成变量,再替换进后续的登录请求。这套流程和上一节的验证码绕过完全同构,学会一个另一个自然就会。

第二种是测试器自带的递归搜索(recursive grep)。攻击类型要设成音叉(Pitchfork),因为 password 和 token 两个字段要同时被替换;token 那个位置的 payload 类型选递归搜索,并设置递归提取内容为正则;请求引擎里把「关注重定向」设为总是。

方案取值来源配置成本失效条件
宏 Macros单独发一次请求拿页面再提取高,要配参数名和 scopescope 设错、参数名不一致
递归搜索上一个响应的正文里直接提低,留在测试器内完成token 不在响应体里、没开重定向跟随

「关注重定向设为总是」这一步常被忽略。登录成功后一般会 302 跳到首页,只有跟着跳过去,下一个请求才能拿到携带新 token 的页面;不跟随,等于一直在用同一个旧 token,跑几万次也是白跑。

2.4 客户端验证码:判断比绕过更重要

这一关比服务端那关简单得多,原文的说法是输入一次正确的验证码、本地校验通过之后,直接按第一种方式爆破即可。原因在于校验发生在前端,服务端压根没验证过这个值。

判断方法有三问:抓登录请求,看请求体里有没有验证码字段;把该字段删掉重放,如果还能登录成功,说明服务端不校验;把验证码改成任意值再重放,仍然成功,那就彻底确认是纯前端校验。三问走完,后面就是普通的表单爆破,不需要宏也不需要递归搜索。这一类关卡的价值不在技巧,而在于建立「校验发生在哪一侧」的直觉,后面遇到前端限制上传类型、前端限制输入长度,用的都是同一套判断。

3. XSS 三形态:输入点、输出点与上下文的对应关系

3.1 反射型 GET 与 POST:一次性回显的两个入口

反射型的关键词是「一次性」:payload 跟着请求进去,跟着响应回来,刷新就没了。原文里 GET 型因为文本框限制了输入长度,所以直接改 URL 里 message 参数的内容,把它换成一个 JS 代码,页面回显时执行;POST 型要先登录,进到页面后抓包拦截,把 message 字段改成<script>alert("xysg");</script>,放包后弹窗。

真正要带走的是「上下文决定 payload」这件事,不是那串弹窗代码本身:

// 输出点在 HTML 正文里:<div>这里</div> var payload_body = '<script>alert("xysg")</script>'; // 输出点在属性里:<input value="这里"> // 先用双引号闭合属性,再引入新的标签 var payload_attr = '"><script>alert(1)</script>'; // 输出点在 <script> 内部:var a = "这里"; // 这时再写 <script> 没用,直接闭合字符串和语句 var payload_js = '";alert(1);//';

三种上下文对应三种写法,用错一种就哑火。这也是很多人「payload 明明没被过滤却不弹窗」的真实原因,问题不在过滤,在闭合方式。

维度反射型 GET反射型 POST
入口位置URL 查询串请求体
手工验证改地址栏即可必须抓包改包或本地构造表单
长度约束受 URL 长度限制通常更宽松
利用形态拼接链接诱导点击需要构造自动提交页面

3.2 存储型与 DOM 型:先确认落没落库、过没过后端

存储型和反射型的差别只有一个:payload 有没有被写进数据库。判断方法很朴素,提交之后刷新页面,内容还在,说明落库了;换一个浏览器或换个会话再访问,内容还在,进一步确认;如果靶场带后台管理页,后台一打开就触发,那就是典型的盲打场景,危害面比反射型大一个量级。

DOM 型更绕,因为抓包看不到 payload 出现在响应里。判断依据是查看网页源代码,搜索自己提交的内容,源码里没有但页面执行了,那就说明是前端 JS 从 URL、referrer 或 postMessage 里取值,再拼进了某个危险函数。下面这段代码把 source 和 sink 的关系摆出来了:

// source:从 URL 里取值,服务端全程没参与 const msg = decodeURIComponent(location.search.slice(1)); // sink:innerHTML 会把字符串当 HTML 解析,payload 在这里执行 document.getElementById("out").innerHTML = msg; // 换成 textContent 就只是文本,标签不会被解析 document.getElementById("out").textContent = msg;

source 到 sink 之间没有服务端参与,这就是 DOM 型抓不到包的原因。复习的时候把常见的 sink 列一遍——innerHTML、document.write、eval、setTimeout 的字符串参数、location 赋值——比记 payload 有用。

3.3 过滤绕过:那些看起来防住了的写法

靶场里的过滤关卡,本质是让你体会「黑名单为什么不是防御」。同样是拦<script>,不同的实现方式对应不同的绕法,思路可以归到一张表里。

过滤方式典型实现绕过思路
标签黑名单只拦<script>换标签,<img src=x onerror=alert(1)>、<svg onload=...>
大小写匹配只匹配小写尝试大小写混写,看解析器是否宽容
关键词过滤拦 alert换 confirm、prompt,或用 eval 拼接
引号转义未使用 ENT_QUOTES输出在属性内时用单引号闭合
长度限制前端 maxlength改前端属性或直接发包

提示:黑名单只能提高门槛,绕过的方向永远比名单多;输出编码加 CSP 才是能落地的防御。

3.4 防御侧:输出编码与 CSP 的落点

复习 XSS 如果不看防御,等于只学了一半。PHP 里最常见的是 htmlspecialchars,三个参数各有含义:第一个是待处理字符串,第二个决定转义哪些引号(ENT_QUOTES 会同时处理单双引号),第三个指定字符集。少写 ENT_QUOTES 时,单引号不会被转义,输出在单引号属性里照样能闭合,这个坑在靶场和真实代码里都很常见。

另一个落点是 CSP 响应头。带上script-src 'self'且不给'unsafe-inline'时,页面里内联的<script>会被浏览器直接拦掉,前面那些弹窗 payload 全部失效:

# 看一眼目标返回的头里有没有 CSP curl -sI "http://target/index.php" | grep -i "content-security-policy" # 期望看到类似:script-src 'self'; object-src 'none' # 如果出现 'unsafe-inline',内联脚本就是放行的,等于没防

需要注意,编码要在输出时做,不要在入库时做。入库时编码,数据会被永久污染,同一份内容在导出、二次编辑、接口返回时会被转义多次,最后显示成一串实体字符。这条经验在靶场里看不出问题,落到实际项目上就是血泪。

4. 注入与执行类:SQL 注入、RCE 与文件包含的重点

4.1 SQL 注入:先分类型,再谈手法

SQL 注入复习的第一步不是背语句,是分清类型。数字型把输入当数字拼,字符型外面包了引号,搜索型是 like 加百分号,还有带括号的变体。类型判断错了,后面的闭合符号就全错,这是手工注入最常见的卡点。

判断流程可以固化成四步:加一个单引号看是否报错;用and 1=1和and 1=2看页面差异;用 order by 递增猜列数;最后用 union select 定位回显位。

-- 第一步:猜列数,n 从 1 往上加,报错前的最大值就是列数 SELECT id, username, email FROM users WHERE id = 1 ORDER BY 3; -- 第二步:定位回显位,前半段查询故意给个不存在的值 -- 前半段没结果,页面才会把 union 后半段的值显示出来 SELECT id, username, email FROM users WHERE id = -1 UNION SELECT 1, database(), version(); -- 第三步:没有回显位时退化成盲注,用真假条件逐位猜 SELECT id FROM users WHERE id = 1 AND ASCII(SUBSTR(database(),1,1)) > 100;

参数上有两个硬约束:order by 的数字表示按第几列排序,超过列数就报错,所以它能用来数列;union 前后两条查询的列数和字段类型必须兼容,一边三个字段一边两个字段,报错直接把你挡在门外。盲注则是页面只剩「有结果/没结果」两种状态时的退路,靠条件真假逐个字符判断,速度慢但没有回显也能走通。

4.2 RCE:命令拼接符决定你能不能接上第二条命令

命令执行类关卡的核心问题是:后端把用户输入直接交给了 shell,还是交给了语言自己的求值函数。前者拼的是系统命令,后者拼的是语言代码,payload 完全不能混用。

# 靶场的 ping 功能,正常输入是一个地址 127.0.0.1 # 分号:顺序执行,不管前一条成功与否 127.0.0.1; whoami # && :前一条成功才执行后一条;|| :前一条失败才执行 127.0.0.1 && id 127.0.0.1 || id

不同系统的拼接符并不通用,;在 Windows 命令解释器下通常不生效,而&、|、||、&&在两边的行为也有细微差别。复习时把「拼接符 → 平台 → 前置条件」当成一张小表记住,比单纯背 payload 靠谱。另外要注意,回显可能有长度限制或者编码问题,命令执行成功了但看不到输出,这时候换成写文件或者带外请求,比反复改 payload 有效。

4.3 文件包含与上传:路径和后缀两道关

文件包含考的是路径能不能被控制。本地包含用相对路径往上跳,远程包含需要目标开启远程文件的包含选项,伪协议则是另一条路:常规包含会把 PHP 文件当代码执行,想读源码就得走 filter 链。

# 读源码而不是执行:先 base64 编码,避免内容被 PHP 解析掉 curl "http://target/vul/fileinclude.php?filename=php://filter/read=convert.base64-encode/resource=config.php" # php://input 配合 POST 体,则可以把请求体当成代码执行 curl -X POST --data '<?php echo "ok"; ?>' \ "http://target/vul/fileinclude.php?filename=php://input"

上传关卡的检查点更多,但思路是统一的:找到检查发生在哪一层,然后决定是绕检查还是绕解析。

检查点表现绕过思路
前端 JS 校验只允许图片后缀改前端属性或直接发包
Content-Type看 multipart 里的类型把类型改成 image/jpeg
后缀黑名单禁止 php大小写、双写、等价后缀
文件头校验调用了图像检测函数伪造文件头,例如加 GIF89a
先存后删有短暂的可访问窗口一边上传一边持续访问

注意:上传关卡真正要过的是「传上去之后能不能被解析」这一关。先确认上传目录能不能直接访问、文件名有没有被重命名,再谈绕过,否则绕过了检查也拿不到执行。

5. 易漏点排查:五个最容易翻车的判断

5.1 偏观察类的三个漏

只测 GET 参数,漏掉请求里的其它输入点。漏的原因是教程演示通常从地址栏开始,眼睛就只盯着 query 串。补法是每关开打之前,把请求里所有可控位置列一遍:query、body、Cookie、Referer、User-Agent、文件名,逐个打标记再验证。很多关卡的回显根本不在页面上,而在后台或者日志里,不列全就永远发现不了。

只测弹窗,漏掉输出上下文。漏的原因是<script>alert(1)</script>太顺手,一不弹窗就判定「有过滤」。补法是先看输出落在哪:正文、属性、script 块、注释、CSS。上下文不同,payload 结构完全不同,属性里要先闭合引号,script 块里根本不能再写标签。把这个判断养成条件反射,能省掉大量无效尝试。

验证码和 token 只测一次就下结论。漏的原因是第一次提交成功,就默认防护失效。补法是多验一步:同一个验证码连续提交两次,看第二次是否被拒;同一个 token 重复使用,看服务端是否校验一次性。只有确认它既不绑定会话也不做一次性校验,才算真的能绕。

5.2 偏工具类的两个错

爆破结果只看响应长度。漏的原因是长度排序最直观,工具默认也按它排。补法是三个信号一起看:状态码有没有从 200 变 302,跳转后的页面里有没有出现登录后的元素,响应时间有没有异常偏离。只按长度排,遇到长度一致但状态码不同的情况,正确的账号密码就躺在列表里被你划过去了。

宏和规则的作用范围没设对。漏的原因是配置项太多,点完就往下走,不回头验证。补法是在正式开跑之前先发一个请求做验证:把线程调成 1,看宏是不是每发一次登录请求就取一次验证码;如果一次没触发或者触发了多次,说明 scope 有问题。这一步花两分钟,能省掉跑完几万请求才发现全失败的后悔药。

6. 复习清单:一页纸自测与查漏补缺

复习到后期,最有用的不是再刷一遍关卡,而是合上教程做自测。下面这张表我按模块列了自测题,答不上来的那一行,就是需要回补的地方。

模块一句话自测卡住说明什么
暴力破解集合炸弹和音叉的区别,什么场景选哪个攻击模式的组合逻辑没吃透
验证码绕过宏的 scope 设在哪,为什么不能设全站只记了步骤,没理解请求链路
token递归搜索从哪个响应里取值,为什么要跟随重定向请求之间的依赖关系没理清
XSS正文、属性、script 块三种上下文各写一个 payload只会背弹窗,没建立上下文意识
SQL 注入order by 和 union 在列数上是什么关系手工注入流程不熟
RCE分号和 && 的执行差异,Windows 下哪些不生效没区分命令与语言的边界
文件包含php://filter 为什么要加 base64不知道伪协议的实际用途
上传「传上去」和「能解析」差在哪一步只关注绕过,没关注落地条件

查漏补缺的具体做法是画图,不是重做。拿一张白纸,对每个模块画四个框:输入点在哪、用什么方式传输、服务端怎么处理、结果输出到哪。画得出四个框并且能连上线,这一关就是真懂了;画到一半卡住,卡住的那个框就是漏洞所在。这个方法比反复刷关卡快,也比看别人的通关记录扎实,因为卡住的位置只有自己知道。

我自己的习惯是,每开一个新靶场,先不急着抓包,强制把这条「输入点到输出点」的连线在纸上走一遍,走不通的关卡标个记号,等做完再回头补。第一轮嫌麻烦跳过这一步,结果同样的坑在 SQL 注入和 XSS 上各踩了一次,第二次才老实。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询