CTF 备赛这件事,最磨人的不是题目本身难,而是你根本不知道自己“该练什么”。刷题平台一大堆,题库上千道,结果今天做一道图片隐写,明天碰一道 Web 注入,后天又看到一个 PWN 题连环境都起不来,刷了一周感觉啥也没学会。这套路我太熟了,因为我自己就是从“瞎刷题”阶段走过来的。
这篇就按我实际备赛的经验,把 CTF 里最常见的几个方向——隐写、密码学、Web、PWN、杂项——拆开讲清楚。每个方向我会写题型的识别方法、通用解题流程、关键工具的具体参数怎么用,再附上我自己踩过的坑。你不用按顺序看完,碰到哪类题不会,直接跳对应章节抄作业就行。
1. 以“题型识别”为核心的备赛思路
1.1 为什么你刷了 100 道题,遇到新题还是不会
很多新手备赛的状态是:打开平台,看到什么题顺眼就点什么。今天做了一道“图里藏字”,明天又做了一道“凯撒密码”,后天挑战了一下 SQL 注入,然后就没有然后了。这种刷题方式的致命问题在于——你练的是“单题解法”,而不是“题型方法论”。
CTF 出题人虽然花样多,但底层逻辑非常固定。隐写题翻来覆去就是文件分离、LSB、二维码修复、LSB 隐写、 NTFS 流这些套路;密码学题来来去去就是古典密码、RSA 变形、分组密码模式;Web 题翻来覆去就是信息收集、注入、文件上传、命令执行、反序列化。你只要在每个方向建立起“题型 → 工具 → 流程”的映射,拿到新题的第一件事就不是乱试工具,而是先判断它属于哪个题型,再用对应套路去打。
我整理过自己的解题知识树,大概长这样:
- 先看文件类型和文件头,判断是图片隐写、压缩包隐写还是流量分析。
- 拿到字符串先试 Base64、Hex、摩斯、凯撒,不行再试维吉尼亚和培根。
- 看到 Web 题先扫目录、看响应头、翻源码注释,再考虑注入。
- 看到 PWN 题先 file 和 checksec,确定架构和保护,再决定打什么漏洞。
这套判断流程比任何工具都重要。工具是死的,判断是活的。题型识别能力上来了,你刷题的效率会翻好几倍。
1.2 备赛要从“刷题量”转向“套路库”
我自己带过几个学弟学妹,发现一个特别明显的现象:练得多的人,拿到题目马上能说出“这题考的是 XX”,然后直接抽工具链开打;练得少的人,拿到题目在那边懵半天,甚至把图片隐写当 Web 题去扫端口。
所以备赛的核心不是堆题量,而是建套路库。每做完一道题,不要急着做下一道,先问自己三个问题:这题考的是哪个方向的哪个题型?解题流程里哪一步最关键?我下次遇到同类题,能不能直接复用这条路径?
我把常见的题型和对应套路列个表:
| 方向 | 常见题型 | 核心工具/方法 |
|---|---|---|
| 隐写 | 文件分离、图片隐写、LSB、二维码、流量包、音频 | binwalk、foremost、zsteg、Stegsolve、Wireshark |
| 密码学 | 古典密码、RSA、AES、哈希、对称加密 | CyberChef、Python 脚本、在线解密站、openssl |
| Web | 信息泄露、SQL 注入、文件上传、命令执行、反序列化 | dirsearch、Burp Suite、sqlmap、蚁剑 |
| PWN | 栈溢出、整型溢出、格式化字符串、堆利用 | pwntools、gdb、checksec、one_gadget |
| 杂项 | 编码转换、社工、取证、流量分析 | 随波逐流、010editor、strings、notepad++ |
这张表就是我说的“套路库”。你不需要背下来,但每做完一道题,就对照表格更新一次自己的认知。等到你能看到题目关键词,就自动联想到工具链的时候,你的备赛才算进入正轨了。
2. 隐写题:从“看图”到“看字节”的思维转变
2.1 隐写题的第一原则:永远先跑一遍“文件体检”
我第一次做隐写题的时候,拿到一张 JPG 图,盯着屏幕看了半小时,愣是没看出哪里有 flag。后来才知道,隐写题的精髓根本不在“看”,而在“拆”。
拿到一个文件,先做三件事。第一,用file命令看真实文件类型,不要相信扩展名。第二,用binwalk扫描有没有附加文件。第三,用strings提取字符串,看有没有明显的 flag 格式或提示。这三步 30 秒就能做完,但能解决 30% 的隐写题。
binwalk 的常用姿势是binwalk file.png直接扫描,如果看到有压缩包或者其它文件的签名,直接binwalk -e file.png提取。foremost 也是做文件分离的,如果 binwalk 分离失败,foremost -i file.png -o output可以按文件签名暴力提取。两个工具配合使用,基本能解决大多数文件隐藏类题目。
还有个容易被忽略的点:文件头被破坏的题。有些出题人会故意改掉文件头,让你打不开图片。这时候用 010editor 或者 HxD 打开文件,看前几个字节。JPEG 的文件头是FF D8 FF E1,PNG 是89 50 4E 47,GIF 是47 49 46 38。文件头不对就改回来,这是隐写入门的第一个常用技巧。
2.2 LSB 隐写:为什么是低位,不是高位
LSB 全称 Least Significant Bit,最低有效位。原理很简单:图片每个像素的颜色值由 RGB 三个通道组成,每个通道 8 位。修改最低的那一位,对人眼来说颜色变化几乎不可察觉,但可以用来藏数据。
为什么不改高位?因为高位一变,颜色变化肉眼可见,隐写就失败了。这就好比在一本书的封皮里夹一张纸条,书的外观看不出异样,但纸条确实在里面。LSB 隐写就是利用了这个“视觉冗余”。
解题工具我推荐 zsteg,一条命令扫描所有通道:zsteg -a 图片文件。它会自动检测 RGB 各通道的 LSB 是否有隐藏数据。zsteg 对 PNG、BMP 支持很好,但对 JPG 无能为力——因为 JPG 是有损压缩,低位数据会被压缩过程破坏。遇到 JPG 的 LSB 题,用 Stegsolve 手动切换通道查看,步骤是:打开图片 → Analyze → File Format 看信息 → Bit Plane 逐个通道翻 → 看到规律数据就 Save 导出。
还有一点要注意,有些题是 LSB 隐写但数据是倒序存储的,导出数据后需要 Reverse 一下字节序再转字符串。我经常在 zsteg 导出数据后先xxd看 hex,确认不是直接 ASCII,再决定要不要反转。
2.3 二维码修复和动图帧提取,这两类题最容易拿分
二维码题也是隐写里的常客。一种是二维码本身不完整,比如三个定位角被抠掉了一个,你需要用 Photoshop 或者在线工具补全。另一种是二维码被做了“艺术加工”,比如在二维码中间加了个 Logo,或者把模块颜色改了,导致扫码失败。
我处理二维码题的经验是:先用手机扫,扫不出来再用工具分析。CQR 在线解码工具对高强度损坏的二维码恢复效果很好,zbarimg 是命令行解码器,zbarimg 二维码.png一条命令就能输出内容。如果二维码是 GIF 或者动态图,记得拆帧——识别动图中每一帧的二维码内容,有些题把 flag 藏在某一帧里。
动图帧提取用的命令是convert 动图.gif 帧_%02d.png,或者用 ffmpeg:ffmpeg -i 动图.gif 帧_%03d.png。拆完帧之后逐张查看,重点看每一帧的二维码或者图片角落的文字。这种题不难,但步骤繁琐,容易漏帧,我个人的做法是先全部拆出来,再统一跑一轮 strings 和二维码扫描,不靠肉眼硬看。
3. 密码学题:识别算法比硬解更重要
3.1 拿到密文先做“指纹识别”,别直接解密
密码学题在 CTF 里占比很大,而且难度跨度极大。简单的是 Base64,难的是 RSA 的各种变形。我发现新手最容易犯的错是:拿到一串密文,直接粘贴到解密网站一个个试,试不出来就懵了。
正确的思路是先做“密码指纹识别”。看密文的字符集和格式:如果是ABCDEFGHIJKLMNOPQRSTUVWXYZ这样的大写字母,可能是凯撒或维吉尼亚;如果是夹杂+/=的字符串,第一反应应该是 Base64;如果是0x开头的一串十六进制,直接转 ASCII;如果是一堆01,可能是二进制转 ASCII 或者培根密码。
CyberChef 是我最推荐的编码转换工具,没有之一。它支持从 Base64、Hex、URL 编码、ROT13 到各种哈希的一键转换,而且是可视化流程操作,可以串联多个步骤。比如你拿到一串 Base64,解出来又是一串 Base64,再解一次就行,CyberChef 拖两个 Base64 模块就能处理。这种“层层套娃”的编码题在入门赛里特别常见,本质就是多层编码叠加。
3.2 RSA 题目从“会调库”开始
RSA 在 CTF 密码学里是重头戏,但考题其实很套路。常见的题型无非这几种:小公钥指数攻击、共模攻击、维纳攻击、已知 p 和 q 直接求私钥。很多时候不需要你真的完整实现 RSA,关键是识别题型之后会调库。
最简单的场景是给了 p、q、e、c,让你求明文。这种题直接用 Python 的gmpy2库:
import gmpy2 from Crypto.Util.number import long_to_bytes p = 123456789 q = 987654321 e = 65537 c = 123456789 n = p * q phi = (p - 1) * (q - 1) d = gmpy2.invert(e, phi) m = pow(c, d, n) print(long_to_bytes(m))这里面最核心的一步是gmpy2.invert(e, phi),用来求 e 在模 phi 下的逆元 d。如果你没有 gmpy2,用 Python 自带的pow(e, -1, phi)也能求逆元,但大数运算速度会慢一些。
共模攻击是另一种高频题型,特征是同一份明文用同一个 n、两个不同的 e 分别加密得到两个 c。解法是用扩展欧几里得算法求出两个指数之间的关系,再组合还原明文。代码模板网上很多,我建议你直接存一份,遇到特征匹配就直接套。
Emmmm,说到 RSA,很多题目还喜欢把 p 和 q 给得很接近,导致 n 可以直接用 Fermat 分解。判断依据是 n 的位数在 512 位左右且 p、q 接近。用 yafu 工具跑一下factor(n),秒出结果。所以拿到 RSA 题,第一件事不是写代码,而是先判断 n 能不能直接分解——很多题就是故意留这个口子。
3.3 古典密码别硬写脚本,先上在线工具
古典密码最大的特点是“手工加密、手工解密”,对应的工具也特别成熟。遇到凯撒密码用 dCode 或者 CyberChef 的 ROT13 模块,遇到维吉尼亚密码用 dCode 的 Vigenere 解码器,遇到培根密码直接搜“Bacon cipher decoder”。
不过古典密码有一个特别隐蔽的坑:Flag 格式。很多题的 flag 不是标准的英文字母,而是flag{...}这种格式,你要在解出来的字符串里找大括号。我做过一道维吉尼亚的题,解出来是一段看起来毫无意义的字母串,结果把首字母和末字母拼起来才是答案——所以古典密码题解完,多留心观察输出文本的结构,比如每隔几个字符取一位。
随波逐流这个工具在 CTF 圈子里口碑很好,它把几十种编码和密码的解码逻辑集成到了一个 GUI 工具里,支持从 Base64 到培根、再到各种生僻编码的一键识别。新手建议直接下载备用。工具本身是 Windows 图形界面,不用配置环境,解压即用,适合比赛时快速验证猜想。
4. Web 题:从信息收集到命令执行的完整链路
4.1 信息收集是 Web 题的生命线
Web 题和别的方向不一样,它极其依赖“信息收集”。很多新手拿到一个 Web 题,直接拿 sqlmap 开始跑注入,跑半天没结果,其实题目考的根本不是注入,而是源码泄露。
我个人的标准操作流程是:先看页面源码,按Ctrl+U,逐行扫注释。然后看响应头和 robots.txt,很多出题人会把提示放在响应头自定义字段或者 robots.txt 里。接着扫目录,用 dirsearch 或者御剑,命令是dirsearch -u 目标地址 -e php,html,txt,重点看有没有.git、.svn、备份.zip、www.zip这类敏感文件。
Git 泄露是 Web 题里特别高频的考点。特征是扫描发现.git目录存在,这时候可以用 GitHack 工具恢复源码,也可以直接访问目标/.git/看能不能列目录。如果源码恢复成功,重点找配置文件里的数据库账号密码、密钥字符串、以及后台逻辑代码里的鉴权漏洞。
还有一个容易被忽略的入口是“报错信息”。你故意输入一个不存在的路径或者格式错误的参数,看页面报错。有的题目会把查询语句直接回显在报错里,这就是 SQL 注入的突破口。我在实际解题中碰到过一种“查询系统”的题,输入 ID 会返回用户信息,但是参数没做过滤,报错信息直接把 SQL 语句打印出来了——这种题本质上就是考试 SQL 注入。
4.2 命令执行题的“最后一公里”是绕过
命令执行题在 Web 方向里属于中高难度,核心是找到一个可以执行系统命令的入口。常见触发点有:ping 功能、文件下载功能、模板渲染漏洞、passthru()函数。
passthru()是 PHP 里直接执行系统命令并输出原始结果的函数,出题人如果在前端留了一个参数拼接到命令里,就形成了命令执行点。比如代码是passthru("ping " . $_GET['ip']),你传ip=127.0.0.1;cat /flag就能在 ping 完之后执行cat /flag。
但现在的题目不会让你这么轻松,常见过滤是删掉空格、过滤;、过滤cat。绕过空格用${IFS}或者%09(Tab 制表符),绕过关键词过滤用拼接技术,比如c""at或者ca\t。我经常用的命令是:
?ip=127.0.0.1|cat${IFS}/flag ?ip=127.0.0.1|ca""t${IFS}/flag如果/flag也被过滤了,可以考虑用通配符:/fl*或者/?[a]g。这属于“最后一公里”的博弈,你在解题时可以从最简单的 payload 开始试,然后看报错回显,再逐层绕过。
4.3 SQL 注入和文件上传,新手最容易“大概会”
SQL 注入是 Web 题最基础的考点,但很多新手只是“大概会”——知道有'和or 1=1,但遇到过滤就抓瞎。我建议新手至少掌握两类:字符型注入和报错注入。
字符型注入的判断方法:输入1'看是否报错,输入1' and '1'='1看是否正常,输入1' and '1'='2看是否异常。如果前两句正常、最后一句反而异常,基本就是字符型注入了。
报错注入适合页面不回显查询结果的场景,用updatexml函数把查询结果带出来,payload 长这样:
1' and updatexml(1,concat(0x7e,(select database())),1) --+这个 payload 的原理是让updatexml的第二个参数包含非法字符~,触发报错的同时把select database()的结果拼在报错信息里。SQL 注入的工具化打法用 sqlmap 就能完成,但我建议新手至少手写一次完整流程,否则根本看不懂 sqlmap 在干什么。
文件上传题的核心是“绕过服务端校验”。最简单的题型是只校验了 Content-Type,用 Burp 把Content-Type: image/jpeg改成application/x-php就能传马。如果校验了文件头,就在 PHP 文件前面拼一张 1x1 的 GIF 文件头GIF89a。上传成功之后,难点变成“马在哪”——你要用前面的目录扫描思路,找到上传文件的路径,然后用蚁剑连接拿到 shell。整条链路是信息收集 → 上传绕过 → 路径确认 → 连接管理。
5. PWN 题:环境配置比漏洞利用更难
5.1 别再折腾了,PWN 环境就这么装
PWN 题劝退了无数新手,不是因为漏洞利用有多难,而是环境配置这一关就够喝一壶的。我见过太多人卡在安装 pwntools 或者启动不了题目给的 binary 上。
建议直接用 Ubuntu 20.04 或者 Kali 作为 PWN 主力系统。pwntools 的安装命令是:
pip install pwntools装完验证一下:
python3 -c "from pwn import *; print('OK')"如果报错,大概率是 Python 环境问题,建议直接用pip install --upgrade pwntools或者考虑用虚拟环境。另外还需要gdb和插件pwndbg,解题时动态调试会方便很多。one_gadget 也是一个神器,在 glibc 2.27 及以下版本的堆题里经常用来直接 getshell。
题目给的目标二进制文件,启动前先做两件事:
file 题目文件 checksec 题目文件file告诉你这是 32 位还是 64 位,有没有动态链接。checksec告诉你开启了哪些保护——重点是 NX、Canary、PIE、RELRO。这四个保护直接决定了你能用什么攻击手法:NX 开启意味着栈上不能直接执行 shellcode,Canary 开启意味着溢出前得先绕过金丝雀值,PIE 开启意味着地址随机化,RELRO 开启意味着 GOT 表只读。
5.2 整型溢出:一个防不胜防的漏洞
整型溢出在 PWN 题里属于“逻辑型漏洞”,不需要复杂的利用链,但非常考基本功。核心原因是:有符号整数和无符号整数在内存里的存储方式不同,当输入值超出类型范围时,会发生回绕。
C 语言里unsigned int是 32 位无符号整数,范围是 0 到 4294967295。如果题目代码写的是:
unsigned int size = 0; scanf("%u", &size); char buf[256]; if (size > 256) { exit(0); } read(0, buf, size);表面看size不能超过 256,但如果你输入一个负数,比如-1,scanf("%u")读进来后会被转换成无符号整数 4294967295,size > 256的判断就会失效,因为 4294967295 显然大于 256——等等,这就不会被拦截吗?
其实这类题的关键往往不是直接负一,而是利用“整数溢出回绕到较小值”。比如判断条件是size < 256就放行,但 read 的长度参数用的却是size - 1之类。你需要构造一个值,让size满足检查,但size - 1变成一个巨大值,从而造成栈溢出。这种题在 Kali 上用 pwntools 写 payload 就特别舒服,你可以这样组织攻击:
from pwn import * context.arch = 'amd64' p = process('./pwn') p.sendlineafter(b'Size:', b'-1') payload = b'A' * 272 + p64(0x4006e6) # 覆盖返回地址 p.send(payload) p.interactive()这里b'-1'的妙处就在于,scanf("%u")读入-1后,size实际等于4294967295。如果判断条件是size < 256,这个输入就会被拦截;但如果判断条件是size < 0或者存在其它类型混淆,就钻了空子。所以做整型溢出题的第一件事,是读源码或者反编译,搞清楚变量类型和比较逻辑,而不是盲目构造 payload。
5.3 栈溢出的核心是“覆盖返回地址”
栈溢出是 PWN 入门第一课,也是最经典的题型。原理代码层面非常朴素:函数在栈上分配了固定大小的缓冲区,gets()或read()往里面写数据时没有限制长度,导致数据溢出,覆盖了栈上的返回地址。一旦返回地址被改成攻击者指定的地址,程序的控制流就被劫持了。
栈溢出的 payload 结构大概是:
padding + 返回地址padding的长度取决于缓冲区距离返回地址的偏移量,这个偏移量的计算有两种方法。有源码的话直接算:比如char buf[64],那buf到栈底的距离是 64 字节,加上ebp(栈底指针)的 8 字节,偏移就是 72。没有源码就用 gdb 调试,在read()处下断点,输入一串特征字符串,看返回地址被覆盖成什么。
pwntools 里有一个专门做这个的函数——cyclic()。生成一串不重复的字符串作为输入,崩溃后用cyclic_find()定位偏移:
from pwn import * payload = cyclic(200) # 跑起来后崩溃,看 gdb 报错里的地址 # 假设地址是 0x6161616e offset = cyclic_find(0x6161616e) print(offset) # 输出真正的偏移量拿到偏移后,把返回地址换成你想要的地址。如果 NX 没开,你可以把 shellcode 放在栈上,返回地址指向栈顶;如果 NX 开了,你得用 ROP 链,调用system("/bin/sh")或者通过puts()泄露 libc 地址再计算system的真实地址。PWN 的难度是递进的,但骨架从来不变:控制返回地址 → 执行目标代码。
5.4 PWN 调试时最容易被忽略的一件事
PWN 题出问题,90% 的情况不是漏洞利用思路错,而是“本地通了远程不通”或者“通了但拿不到 shell”。最常见的原因是 libc 版本不一致。
本地 Ubuntu 的 glibc 版本和题目服务器的不同,system函数在 libc 里的偏移就不一样。你本地算的地址是错的,远程自然打不通。解决办法是用题目给的 libc 文件,用pwninit或者手动 patch:
patchelf --set-interpreter ./ld-2.27.so 题目文件 patchelf --set-rpath . 题目文件这样本地运行用的就是题目提供的 libc 环境,调试结果才能和远程一致。这个坑我踩了不止一次,强烈建议你在做任何 PWN 题时,提前确认题目有没有提供 libc 附件。
6. 杂项和工具链:备赛效率的隐形分水岭
6.1 随波逐流这类集成工具,为什么高段位选手也在用
很多人对“工具箱”有偏见,觉得高手都是纯手动。实际上 CTF 比赛时间紧迫,能用工具一分钟解决的事情,绝不用脚本二十分钟解决。随波逐流这个工具集成了编码、哈希、古典密码、隐写解码、甚至部分取证功能,相当于把几百个独立小工具压缩进了一个 GUI。
我个人的使用习惯是:拿到一段可疑字符串,先丢进随波逐流点“自动识别”,如果它识别出来了,直接看结果;如果识别不出来,再用手动流程分析。这不丢人,反而特别高效。工具的意义在于帮你缩小范围,而不是替代你的思考。
CTF 练习网站方面,国内免费平台做得比较成熟的有:CTFShow、攻防世界、BUUCTF 等。CTFShow 的题目分类很细,适合按知识点定向练习;BUUCTF 的题目复现比较多,适合刷真题。备赛建议不要贪多,选一个平台主刷,每个方向刷到 20 道以上,形成手感之后再换平台。
6.2 流量包和取证的“三板斧”
杂项方向里的流量包分析,其实就是 Wireshark 三板斧:先看协议分级,再追踪 HTTP 流,最后筛可疑的 DNS 请求。http过滤出所有 HTTP 包,tcp.stream eq 0追踪第一条 TCP 流——很多题目直接把 flag 放在某个 HTTP 响应体里,连隐藏都没藏。
取证题则要留意“隐藏文件”。Linux 下隐藏文件以.开头,Windows 下可能有 NTFS 数据流。前者用ls -la查看,后者用dir /r查看。有一种经典的 NTFS 流隐写做法,是在正常文件后面藏数据流,你用notepad.exe 文件:流名才能打开看到内容。这类题在取证方向里很常见,难度不高但很考细心。
6.3 做题习惯才是备赛的真正分水岭
最后说一个容易被忽略的、但特别影响实战发挥的问题:命名规范和过程记录。比赛现场时间紧、题目多,如果你连自己解到哪一步都记不清,效率会大打折扣。
我的习惯是每个题目建一个文件夹,里面放题目附件、解题脚本、解题 writeup 草稿。脚本命名按“功能+版本”来,比如solve_lsb_v2.py,避免出现“最终版本最后最终版”这种悲剧。writeup 无论多长都要写,因为写 writeup 的过程就是复盘,很多当时没注意的细节,都是在写 writeup 的时候想通的。
7. 从备赛到正式比赛:一些越早知道越好的经验
7.1 比赛前三天不要学新东西
大赛前三天,不要再碰没见过的题型,更不要临时学新工具。这个阶段的重点是“保持手感”——把每个方向最熟悉的题各挑两题,完整打一遍流程,把常用的命令和 payload 过一遍,确保手不生。
临时学新东西最大的风险是:你只知道皮毛,比赛时用了反而浪费时间,还容易把环境弄崩。我见过有人在比赛开始前半小时还在装新工具,结果比赛刚开始环境就坏了,白白浪费一上午。备赛是长跑,不是冲刺,最后三天的心态应该是“稳稳拿分”。
7.2 比赛时的“时间分配”策略
CTF 比赛的时间分配和平时刷题完全不一样。比赛追求的是总分,不是单题的深度。我的策略是:前 30 分钟把所有题目的附件都下载一遍,快速看题面,标记出“能做的题”;优先打自己有把握的题型,把确定性分数先拿到手;一道题卡了 30 分钟还没有进展,果断换题,不要死磕。
信息收集类的题永远是最划算的,因为耗时短、成功率高。PWN 题如果环境复杂、附件残缺,可以放到后面再碰。比赛的节奏控制,本质上是一次“投入产出比”的管理。
7.3 赛后一定要做的一步
比赛结束不等于学习结束。赛后复盘比比赛本身更重要。复盘时要做两件事:第一,整理所有题目的解法,不管是你做出来的还是没做出来的;第二,做错的题和没做出来的题,要找到对应知识点的漏洞,补充进你的套路库。
复盘不是抄 writeup 就完事,而是要把别人的解法用自己的语言讲一遍,再做一遍。只有亲手写过的 payload、亲手解过的密文,才是你的。下一次比赛遇到同样的题型,你只需要说一句:“这题我学过。”
CTF 备赛说到底是一个“建立系统”的过程。你不需要把所有方向都练成专家,也不可能在几个月内做到样样精通,但你需要知道每类题型的入口在哪、常规打法是什么、工具链怎么搭配。这套认知建立起来之后,刷题就不再是瞎刷,比赛也不再是碰运气——你是在用自己的方法论解题,而不是用题库的运气解题。