1. 赛前准备清单:为什么我最终选了这套练手靶场组合
2026 i春秋冬季赛的报名信息一放出来,我第一反应不是去看赛制说明,而是先翻了翻自己半年来刷过的靶场记录。说句实话,i春秋的比赛题目风格这些年变化挺大的,从早期的纯CTF套路题,慢慢变成了“贴近实战场景但是又保留CTF解题逻辑”的混合型命题。如果赛前一周才开始临时抱佛脚,基本就是去当炮灰。
我这次赛前准备分了三层:第一层是基础漏洞靶场,把Web方向常见的漏洞类型过一遍手;第二层是带权重的综合靶场,模拟真实业务系统里的多点串联利用;第三层才是比赛真题回顾,把i春秋历届冬季赛里出现过的出题套路捋一遍。
基础漏洞靶场我选了DVWA和Pikachu。为什么是这两个?因为它们都是开源、能在本地用Docker一键搭起来的,而且DVWA的漏洞等级分低中高三个档位,适合从原理到绕过分层递进;Pikachu则更贴近国内CTF比赛的出题习惯,比如它的RCE、文件包含、SQL注入这些模块,基本就是国内比赛题的简化版,刷完它再去看i春秋的Web题,起码不会对着题目发懵。
Docker搭建这个过程我要多说一句,因为很多人卡在环境上而不是题目上。我当时用的是kali里直接跑Docker的方式,命令很简单:
bash复制docker run -d --name dvwa -p 8080:80 vulnerables/web-dvwa
跑起来之后访问http://localhost:8080就能进DVWA的登录页,默认账号密码是admin/password。Pikachu的话,官方仓库clone下来之后,有现成的Dockerfile,直接docker build就能起。唯一要注意的是Pikachu的数据库初始化脚本需要PHP环境支持pdo_mysql扩展,如果你用的是默认镜像,大概率已经装好了,但是如果自己改过PHP配置,这一步会是第一个坑。
综合靶场我刷的是upload-labs和sqli-labs,这俩也是Docker一键起。upload-labs专门练文件上传绕过,从前端JS校验到服务端MIME校验、黑名单后缀、图片马、二次渲染,一共21关,每一关都对应一种真实场景里的上传过滤逻辑,刷完基本能把上传漏洞的绕过思路理顺。sqli-labs则是从数字型注入、字符型注入、报错注入到时间盲注,1-65关全过一遍之后,SQL注入的手工判断能力会有明显提升。
上传和注入为什么会成为练手重点?因为i春秋的比赛题目里,Web题有一半以上都绕不开这两个点。要么是登录框存在SQL注入,要么是后台存在文件上传,前者用来拿权限,后者用来留后门,两个点结合就是一条标准的Web攻击链。如果你连这两个基础模块都需要现查笔记,那比赛四小时基本不够用。
至于为什么没选vulnhub,是因为vulnhub的靶机更偏向内网渗透和整体思路训练,单关时长普遍在两小时以上,和比赛这种“短平快拆题”的节奏不太匹配。vulnhub适合放在比赛之后作为进阶,不适合赛前冲刺。这是我的个人判断,不代表所有人,但对于目标是“在i春秋冬季赛里拿保底分”的选手来说,基础靶场刷熟练度的优先级肯定高于打整台vulnhub机器。
赛前最后一天,我把kali里的工具清单重新过了一遍:Burp Suite的抓包改包、sqlmap的Tamper脚本、nmap的常用扫描参数、蚁剑和冰蝎的连接方式、还有John the Ripper做弱口令爆破。这些工具的熟练度,决定了你在比赛里能不能快速从“发现漏洞”走到“拿到flag”。很多人比赛失败不是因为不会漏洞原理,而是因为工具用得太慢,比如一个Base64编码的数据包,手工改要两分钟,用Burp的Decoder模块十秒就搞定,这个差距在分秒必争的比赛里会被无限放大。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三个最容易上分的Web题:从源码审计到SQL注入绕过
正式比赛开始之后,我按惯例先把Web题全部点开看了一遍,不急着上手,先判断每道题的难度和目标环境。这一轮信息收集非常重要,我见过太多人一上来就拿着sqlmap扫全场,结果把简单的源码审计题打成了盲注题,浪费时间不说,还可能把题目环境打坏。
第一道Web题给的是一个登录页面,附带一个.tar.gz源码包下载入口。这个题目设计很典型,就是考察选手会不会做源码审计。我把源码包下下来解压之后,发现后台逻辑写在一个admin.php文件里,大概结构是这样的:
php复制$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
注意这里没有用参数化查询,直接字符串拼接,百分百存在SQL注入。但问题在于,题目的登录框有一个前端JS校验,会拦截单引号,所以直接在页面上测试是打不进来的。绕过方法有两种:第一种是用Burp Suite拦截请求,直接改POST数据包,前端的JS校验形同虚设;第二种是看源码里的注释,出题人一般会留下提示,比如在config.php里写着“修改密码请通过admin接口”,这其实就是在暗示后台路径。
我选择了Burp改包的方式,在用户名处填入admin' or '1'='1,密码随便填,然后放包。返回结果直接跳转到了后台管理页面,说明注入成功。这个题几乎就是原封不动地把DVWA的低难度SQL注入搬到了比赛里,只不过加了一层前端校验做障眼法。如果你在赛前认真刷过DVWA,这个题应该在十分钟内拿下,没有任何悬念。
第二道Web题是一个文件上传功能,风格特别像upload-labs的某一关。题目页面上传了一个PHP后门文件,后缀名是.php,结果直接被前端拦截,提示“文件格式不允许”。这里的拦截规则我看了一下,前端JS只校验了后缀名,而服务端对后缀名的校验用的是黑名单,把php、php3、php5、phtml这些常见后缀全部拉黑了。
但黑名单有个致命弱点,就是漏掉了一些非常规后缀,比如.pht和.phar。我把文件名改成了shell.pht,内容写的是标准的一句话木马:
php复制<?php @eval($_POST['cmd']); ?>
上传成功之后,用蚁剑去连接这个文件,连接密码设成cmd,直接拿到了网站的WebShell权限。在WebShell里翻了一下目录,flag放在/var/www/html/flag.txt里,直接读出来提交,这个题收工。
这道题想表达的核心内容是:黑名单校验永远不是安全的,服务端必须做白名单校验,而且要把文件内容也检查一遍。比赛里它考的就是你有没有见过这类绕过方式。如果你只刷过DVWA,可能不知道.pht后缀这回事;但如果你刷过upload-labs的后半段关卡,看到这道题的那一刻就能秒出答案。
第三道Web题是整套卷子里最容易拿分的一题,因为它是个登录绕过,但是出题人把登录失败的逻辑写错了。
登录接口的逻辑简化后是这样的:
php复制if ($row) {
if ($row['password'] === $password) {
echo "success";
} else {
echo "password error";
}
} else {
echo "user not found";
}
正常情况下,这个逻辑没问题。但出题人在这道题里加了一个用户枚举的漏洞:只要用户名存在,就算密码错了,返回的错误提示也是“password error”;如果用户名不存在,返回的是“user not found”。这样等于白送了一个用户名枚举接口。更致命的是,管理员账号的密码强度很弱,出题人用了admin123,我用Burp的Intruder模块加载了一个常见弱口令字典,直接爆破密码,几秒钟就出来了。
这个题的考点其实是“弱口令+用户枚举”的组合拳,属于最基础的Web安全场景。但它能出现在冬季赛里,说明主办方希望选手别光盯着SQL注入和文件上传,也要关注业务逻辑层面的漏洞。说实话,我在刷Pikachu靶场的时候,里面的“越权访问”和“密码重置”模块就是练这个的,只不过Pikachu里没有用Burp爆破这一步,比赛帮我把这个短板补上了。
这三道Web题拿下来,我已经有了三道flag的分数,按照往年的分数线,这基本可以确保不垫底了。但Web题并不是全部,后续的逆向和Pwn才是拉分的关键。
3. 逆向与Pwn题里的卡点:一个坑位花了整晚
如果说Web题是基础分,那逆向和Pwn就是真正的修罗场。我赛前练逆向的时候,刷了不少安卓逆向和简单CrackMe,但i春秋的逆向题风格很杂,有的考算法逆向,有的考安卓加固,之前搜索里提到的“安卓逆向靶场”我也试过,但和比赛难度相比,还是有点差距。
这次的逆向题有一道是Windows PE文件,运行之后提示输入Key,输入正确就显示“Congratulations”。我按老思路,先用strings命令扫了一遍,没发现明显的明文字符串;再用IDA打开静态分析,定位到关键比较函数。
这里就遇到了第一个卡点:出题人把关键字符串做了异或加密。我一开始在IDA里看到的都是乱码,完全找不到比较的临界值。后来我才反应过来,在代码里有一段循环,逐字节把输入的内容和一个固定key做异或运算,然后把结果存到另一块内存里比较。我通过动态调试,在比较函数处下断点,直接读内存,拿到了参与比较的目标字符串,然后用Python脚本逆向还原出了正确的输入:
python复制enc = [0x11, 0x24, 0x37, 0x0A, 0x52, 0x67, 0x79, 0x3C]
key = 0x77
flag = ''.join(chr(c ^ key) for c in enc)
print(flag)
说实话这样的算法在逆向题里算很简单的,难点在于你能不能识别出“异或加密”这个套路。如果你没有逆向经验,看到乱码字符串会以为关键逻辑在别的地方,然后绕一大圈,最后还找不到正确结果。我个人的心得是:看到可疑的循环、异或指令、再加上一串奇怪的十六进制数据,优先尝试异或解密,这比硬啃整个程序逻辑效率高得多。
Pwn题就更让人头大了,这次的Pwn题是一道栈溢出题,程序是64位ELF,开启了NX(栈不可执行)和Canary(栈保护)。我打开IDA看了一下,目标函数里有一个read(0, buf, 0x100)的调用,但buf大小只有0x20,明显存在栈缓冲区溢出,但是Canary保护在函数返回前会做检查,导致我的第一个payload直接触发了__stack_chk_fail,程序崩溃了。
这里我要详细说一个坑,也是我整个比赛里耗时间最长的地方。
Canary绕过的常规解法是泄露Canary值,然后再构造payload。泄露的方法通常利用程序中有puts或printf输出输入数据的漏洞,通过打印输出到缓冲区外的数据,把Canary带出来。但这个程序并没有直接输出,只给了两次输入点。于是我查了一下,发现程序里有一个隐藏的backdoor函数,里面直接调用了system("/bin/sh")。这意味着只要我能拿到shell,flag就能直接读。
思路就变成了:第一次输入时,把输入填充到Canary前面的位置,再发送一个字节,触发read的返回,导致Canary的最低字节被覆盖(因为Canary最低字节是\x00),然后程序在返回前验证Canary时会失败,但失败前会调用__stack_chk_fail,而__stack_chk_fail里面会调用__libc_message,进而打印出一些错误信息,其中可能包含了栈上的Canary部分内容。
这个思路理论上可行,但实际调试的时候,小端序和偏移计算搞了我很久。我最后用的方法是:先输入0x20个A填充buf,再加上一个换行符,让read刚好读到我们想要的长度,然后程序在输出时会把Canary打印出来。我通过GDB调试,在Canary检查处下断点,直接从栈上读出了Canary值。
拿到Canary后,第二段payload就比较简单了:
python复制from pwn import *
# 假设canary的值已经泄露出来
padding = b'A' * 0x20
payload = padding + p64(canary) + b'B' * 8 + p64(backdoor)
sh.sendline(payload)
sh.interactive()
把Canary放回去,再覆盖返回地址到backdoor函数,就能拿到shell。这套操作在Pwn题里属于基础操作,但考场上因为紧张加上GDB调试不熟,我硬是花了快一个小时才跑通。坦白讲,如果赛前我把这道题的逻辑在本地靶机多练几遍,应该能省下二十分钟。
这场比赛打下来,我对逆向和Pwn的最大感受是:题目本身不难,难在你要在比赛时间里保持清晰的头脑,把所有步骤都记熟。很多Pwn工具脚本的写法,比如p64、p32、flat拼接这些,赛前两天练到形成肌肉记忆,赛场上才能不卡壳。
4. Misc与取证题:被忽略的流量包里捡分
很多选手打CTF比赛习惯性地优先冲Web和Reverse,把Misc和取证题留到最后看心情做。我在前几届比赛里也犯过这个错误,但这次我特意留了半小时给Misc题,结果确实捡了漏,有一道题几乎就是送分。
这道Misc题给了一个pcapng流量包文件,要在里面找flag。我拿到包之后,先用strings扫了一遍,没用,没有直接暴露的flag格式字符串。接着用Wireshark打开,先按流量大小排序,发现有一个HTTP流格外大,点进去看了下,是一个文件下载的响应。我用Wireshark的“导出HTTP对象”功能,把这个文件导出来,一看文件头是PK开头,是个Zip压缩包。
解压的时候发现压缩包有密码,密码提示写在一个TCP流里:password: p@ssw0rd。输入密码解压成功,里面是一个txt文件,内容就是flag。整个流程五分钟搞定,难度基本为零。
但这个题让我想到一个很容易踩的坑:如果你只盯着Wireshark的界面看http内容,忽略了TCP流里夹杂的明文密码,那这个Zip就永远解不开。我见过很多人在这个题上浪费大量时间,用Ziperello暴力破解密码,其实密码就在流量里等着你看。
Misc题的另一类常考方向是图片隐写。这次有一道题给的是一张PNG图片,用binwalk扫描了一下,发现尾部有一个附加的RAR文件。我用binwalk -e解包,提取出了RAR压缩包,解压后得到一张看起来一模一样的图片。两张图片大小不同,我用compare命令做像素对比,发现有几行像素不一样,把差异像素转成ASCII字符,拼出了flag。
这个思路听上去很专业,但其实它完全可以在赛前通过刷题练出来。类似的隐写手法,在Pikachu靶场里没有,但在专门做隐写题的平台上很常见。如果你想要在Misc题上拿分,建议比赛前专门找一个隐写题合集,把binwalk、steghide、zsteg、LSB隐写这些工具的常用命令记熟练,比临时翻笔记快得多。
说到取证题,最近搜索热词里反复出现“数证杯电子取证wp”,这个比赛方向确实越来越火。虽然这次i春秋冬季赛的取证题不多,但有一道是关于模拟手机备份文件的。题目给了一个Android备份文件,内容是一个db数据库,里面记录了通讯录、短信和应用数据。flag藏在短信记录里,但是经过了Base64编码。我用sqlite3命令打开数据库,查出短信表的数据,把内容Base64解码之后得到了flag。
这种题的技术含量不高,但考察的是你对常见取证文件格式的熟悉程度。比如Android备份文件解压用什么命令、sqlite3怎么查表、常见编码怎么识别,这些都是可以短时间练出来的。比赛时间分配上,我建议留出至少半小时给Misc和取证,因为在大家技术水平差不多的情况下,这种题就是纯粹的熟练度比拼,谁练得多谁拿分快。
顺便提一句,如果有人问你“国内有哪些网络靶场”,那我这次的推荐排序是:入门选DVWA和Pikachu,进阶选sqli-labs和upload-labs,综合实战推荐红日靶场和vulnhub。红日靶场的第二季和第一季我都刷过,第一季是标准的域渗透环境,适合赛前模拟内网横向移动的场景;vulnhub则是各种难度分层的真实漏洞环境,对提升综合渗透能力帮助很大。不过这些靶场的题目难度普遍高于i春秋的正式赛题,练的时候如果卡住了,别气馁,比赛只会比这更简单。
5. 冬季赛整体观察:出题风格与明年备赛策略
整场比赛刷下来,我最大的感觉是:i春秋冬季赛的难度设置其实是有意做了分层的。Web题平均难度中等偏下,目的就是让绝大多数选手都能上手拿分,不至于出现三小时零解的情况;逆向、Pwn题则是中等偏上,用于区分“刷过题”和“真懂原理”的选手;Misc和取证题属于锦上添花,考察的是广度和工具熟练度,不需要你有多深的漏洞原理功底,但要求你见过足够多的题型。
结合今年和往年的题目对比,我总结出几个出题趋势,供明年要参赛的朋友参考。
第一个趋势是业务逻辑漏洞占比明显上升。以前比赛基本都是标准注入、标准上传、标准XSS,但现在越来越多的Web题会加一层业务场景,比如用户枚举、验证码绕过、密码重置逻辑缺陷、越权访问。这些东西在DVWA和Pikachu里其实都有对应模块,但很多人只盯着SQL注入和文件上传刷,忽略了业务逻辑的部分。建议备赛时把Pikachu的“越权访问”、“密码重置”、“验证码绕过”这几个模块单独过一遍,不用深入,但至少要能看出题目的意图。
第二个趋势是工具链的熟练度越来越重要。今年的Pwn题,如果你用pwntools写脚本不熟,可能光调试就要花一个小时;如果你对Burp Suite的Intruder模块不熟,那弱口令爆破题就会变成手动输入,效率低得离谱。我建议在赛前一个月,把所有常用工具做一个“盲操训练”:不看笔记,光凭记忆把sqlmap指定目标、指定参数、指定数据包的完整命令写出来;把Burp的代理、Repeater、Intruder流程跑一遍;把蚁剑的三种连接方式都试一次。这些熟练度不会浪费,比赛的时候就是纯赚时间。
第三个趋势是环境搭建能力被低估了。很多人以为比赛不会考环境搭建,实际上如果你整个赛前阶段连DVWA都不会用Docker搭,那你的练习量一定上不去。我在赛前用Docker搭靶场的过程里,接触到了一些Linux基础命令、端口映射、容器管理、日志查看,这些东西在我比赛过程中排查环境问题时给了很大帮助。比如有一次我的sqlmap连接超时,我第一反应是去看目标端口是否开放,而不是盲目重试,这就是反复搭靶场带来的经验。
如果你准备参加明年的冬季赛,我建议你按这个顺序备赛:先用两周刷完DVWA的高难度Web漏洞模块,熟悉漏洞原理和手工验证流程;再用一周刷完Pikachu的全部关卡,重点理解题目场景和出题意图;接着花两周刷upload-labs和sqli-labs,把上传绕过和注入的手法练成肌肉记忆;最后在赛前一周,用一两个vulnhub靶机做模拟赛,检验自己的综合时间管理和工具熟练度。这套组合拳打下来,只要正常发挥,Web方向的保底分是能拿到的。
至于逆向和Pwn,我的意见是:如果你是Web方向选手,不要把大量时间花在Pwn上,因为你短期内的回报率很低。但你至少要会看一个最简单的栈溢出,知道p64和p32是什么意思,能跑通一个最简单的栈溢出demo。因为比赛的时候,你会遇到那种无人解题的Pwn题,这种题通常有一个极为明显的溢出点,如果你能拿下一血,分数加成是非常大的。我不是鼓励你硬啃Pwn,而是建议你把门槛定在“能解最简单的一题”就好。
比赛结束之后,我又把这次踩过的坑整理了一遍,比如Canary泄露的步骤、.pht后缀上传绕过、Zip密码隐藏在TCP流里这些细节,单独记了一个笔记文件。这些笔记在下次比赛前拿出来复习一遍,效果比临时抱佛脚强太多。
最后分享一个小经验:赛前别刷难题怪题,比赛的时候也别死磕一道题超过四十分钟。如果一道题超过四十分钟没有进展,果断换下一道,把会做的先做完拿分,再回头啃硬骨头。这次比赛我就是靠这个策略,在最后半小时捡漏了Misc题的flag。如果你选择硬刚Pwn题死磕两小时,很可能最后连Misc送分题都没时间碰,那才是真正的亏。
