ctfshow内部赛这几个月我前前后后打了三场,说实话,比很多公开赛来得过瘾。你说它是“内部赛”,但题目质量和思路完全不输对外的大型赛事,甚至因为参赛人数有限、氛围更聚焦,反而更能逼着你去抠细节。从第一场的茫然摸索,到第三场能稳住节奏按部就班地解出两三道题,整个过程让我对CTF的理解上了一个台阶。今天这篇就把我这几场内部赛的亲身体验、踩坑和复盘思路完整写下来,不管你是刚入门的新手,还是已经打过几场公开赛想进阶的老手,应该都能从中找到点值得拿走的东西。
1. 内部赛到底是什么:为什么它比公开赛更值得琢磨
1.1 从公开赛到内部赛的差异
ctfshow本身是一个以CTF题目为核心的学习平台,日常对外开放的比赛不少,题目覆盖Web、Pwn、Reverse、Crypto、Misc等经典方向。而所谓“内部赛”,通常是指平台针对核心用户群、技术社群或合作团队举办的小规模比赛,不向所有路人开放,题目数量不多(一般5到10道),比赛时长从两小时到半天不等。
我第一次参加时以为内部赛只是公开赛的“精简版”,甚至可能更简单。打完之后发现完全不是那么回事。公开赛由于参赛者基数大,往往会设置一定比例的“送分题”来照顾新手体验,哪怕是难题也会因为人多、集体讨论多而出现大量爆破式解出。内部赛则不同,参赛者基本都是有一定基础的老面孔,没有明显的阶梯教学意图,题目更偏向于“真实环境中会遇到的问题”和“命题人最近关注的技术点”。举个例子,某场内部赛中有道Web题,表面是个新闻发布系统,但核心漏洞点藏在Nginx的错误配置和前端JS压缩后的注释里,这种组合在公开赛里很少见,因为需要参赛者跨知识点联想。
另外,内部赛的排行榜和赛后反馈通常也更直接。我在公开赛里提交flag后,往往只知道“对或错”,但内部赛有时会给出每个环节的得分比例,比如“你找到了源码,但没利用成功,得20%分”。这种颗粒度的反馈对复盘非常有利,能清楚地看到自己卡在哪一环。
1.2 内部赛能锻炼哪些能力
我觉得内部赛最大的价值不是“得奖概率”,而是“能力验证”。公开赛里你可以靠搜索引擎、团队配合、甚至运气蹭到一些分,但内部赛因为题目少、人群聚焦,每个解题步骤都得自己走通。它会强迫你在几个特定方面变强:
一是信息收集能力。内部赛题目往往不直接告诉你漏洞在哪,而是给一个域名、一个附件、一段流量包,你需要自己通过目录扫描、源码审计、流量分析等手段把攻击面摸清楚。这跟真实渗透测试的流程非常像。
二是跨方向迁移能力。CTF分类虽细,但内部赛经常会出现“Web+杂项”或者“密码学+逆向”结合题。比如一道看起来是Misc的图片隐写题,最后却要你用RSA私钥解密一段AES密文,而私钥又藏在另一个附件里。这种连锁题在公开赛里也有,但内部赛的线索埋得更深,需要你跳出单一方向思维。
三是时间管理和心态控制。因为题目少,总时长固定,一旦卡题就会非常焦虑。我第一场内部赛就在一道Reverse题上耗了快四十分钟,结果是动态调试时忘了改寄存器数据,一直没走到正确分支。后面我才学会“每道题最多投入20分钟,没进展就先换题”的节奏策略。
2. 赛前准备:环境、工具和心态都要调到战斗状态
2.1 环境与常用工具清单
虽然内部赛不对外公开报名,但如果你有机会参加,赛前准备一定要按“真实渗透测试”的标准来。我一般会提前准备一套已经调试好的虚拟机环境,避免比赛开始后还在装依赖。
我的推荐清单可分为三层:
第一层是网络代理与抓包工具。Web题必备Burp Suite,至少要熟悉Proxy模块和Repeater模块。内部赛经常考HTTP请求伪造、JWT伪造、SSRF等,没有Burp的拦截和修改能力很难做。同时备一个Wireshark,因为Misc题喜欢给pcap流量包,你可能需要过滤HTTP流或TCP流来恢复文件。
第二层是逆向和漏洞分析工具。对于二进制题,Ghidra和IDA Free是主力,我习惯先把程序拖进Ghidra看伪代码,定位关键函数,再用gdb或pwndbg做动态调试。对于Java类Web题,可以备一个Java反编译器(如jd-gui)来快速看class文件。不要忘了Python环境,里面装好z3、pwntools、pycryptodome、requests、Pillow等常用库,很多算法和编码题都要靠它们。
第三层是编码与杂项处理工具。CyberChef是永远的神,Base64、Hex、URL编码、Rot13、AES解密、文件特征分析这些操作在网页上点几下就行。另外备着一个十六进制编辑器(010 Editor或HxD),用于手工修复文件头、分析二进制隐写。
提醒一下:工具不是装得越多越好,关键是熟练。我见过有人比赛时开着十几个工具,却连Burp的Intruder模块怎么用都要现场查,这等于端着武器不会开枪。
2.2 针对性训练:从公开赛题目中提炼规律
内部赛虽然题目新,但命题人的思路往往一脉相承。如果你平时在ctfshow公开赛里已经做过不少题,赛前可以快速刷一遍近期的公开赛题解,尤其是那些“非传统”的题目。比如如果最近公开赛频繁出现“通过修改HTTP头里的X-Forwarded-For来伪造IP”的题,内部赛大概率也会有一道类似的,只是会换个实现方式。
我自己的训练方法是:把每道练过的题按“考点标签”分类,例如“SQL注入+过滤绕过”“PHP伪协议+文件上传”“RSA中低指数攻击”“ELF花指令混淆”等。赛前花半小时翻一遍这些标签,相当于给自己列一份“考点清单”。比赛时遇到题目,先在脑海里映射到对应标签,能节省大量试探时间。
另外,内部赛考的工具链往往不限于CTF圈子常见的那些。比如有一次比赛第一题就是“通过分析微信小程序包提取加密参数”。这种题在传统CTF里不太出现,但内部赛因为受众面小,命题人敢玩一些新花样。所以赛前最好了解一下移动端抓包、小程序解包、JSONP劫持等冷门知识,不一定精通,但至少知道工具是什么。
3. 实战拆解:我过的一道典型题目全过程
3.1 Web题:一个看似平平无奇的登录点
第二场内部赛有一道Web题,题目叫“签到中心”,打开就是一个登录框加一个验证码,看起来没有任何特殊功能。我最初尝试了常见SQL注入,比如用户名填admin' or 1=1--,发现验证码会刷新而且提示“参数错误”。因为我只修改了用户名,没有同步更新验证码,所以被拦截了。
接着我按常规思路进行目录扫描,扫到了/robots.txt,里面有个不显眼的/api/debug路径。访问后返回一个JSON,里面列出当前用户的会话结构,包括session_id和role字段,role是“guest”。这个发现让我意识到登录逻辑可能不是简单的SQL注入,而是靠服务端维护一个序列化对象或JSON令牌。
我顺着这个思路,用Burp抓了登录请求,发现提交的参数是data=eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6Imd1ZXN0In0=,解码后是个base64编码的JSON。所以真实逻辑是:前端把用户信息和角色打包成base64发给后端,后端解析后直接决定权限。我只需要把这个JSON里的role改成admin,再重新base64编码提交,就拿到了管理员接口。
但flag并不在接口返回里。我看到管理员接口有“导出用户日志”功能,下载的excel文件名是logs_2025.xlsx,用unzip解压后发现里面除了正常的sheet外,还有一个隐藏的XML文件,其中插了一段注释,内容是一个URL路径/flag/list。访问这个路径需要带管理员token,而这个token就在之前登录响应的cookie里。最后把token粘贴进去,成功拿到flag。
这道题本身不难,但胜在链条长。它让我意识到,内部赛的Web题很少只有一个漏洞点,往往是“信息泄露→会话伪造→越权→二次信息隐藏”的组合,每个环节的线索都在引导你去下一个点。
3.2 杂项题:藏在流量包里的另一个世界
另一道让我印象深刻的Misc题只给了一个capture.pcap,没有额外描述。一开始我用Wireshark打开,快速浏览协议分级,发现HTTP请求不多,有大量USB协议数据。这通常意味着题目和键盘敲击记录有关,特别是USB HID数据包,可以还原出用户输入的按键。
不过仔细看,这些USB包不是标准的键盘接口数据,它们的传输大小是16字节,比常见的8字节多了一倍,而且里面除了键盘按键,还混着鼠标事件。我尝试用普通USB键盘脚本去解析,结果全是乱码。后来我写了个Python脚本,按照设备地址过滤出其中一种接口流量,然后用HID键值对照表解析,得到一段看起来像密码的字符串:Qwerty!234。我一开始以为它是某个压缩包的密码,但直接解压并不对。
我又回去看Pcap,发现有一个HTTP POST请求把一段加密字符串传到了某个内网地址。响应里是一个文件下载地址。我下载下来是一个ZIP文件,用刚才得到的密码去解压,成功了。里面是一个文本文件,内容是Base64编码的多层嵌套。我复制到CyberChef里,用“From Base64”递归解码了四次,最后得到flag。这道题考的不是单一隐写技巧,而是“流量分析→USB协议理解→密码复用→多层编码”的全过程。卡点主要在USB解析上,因为我对HID协议不如网络协议那么熟,当时临时查了键值映射表才搞定。
3.3 一则经验:不要轻视Crypto和Reverse的基础题
内部赛同样会有一两道Crypto或Reverse题,但它们的定位往往不是“比算法复杂度”,而是“比代码审计的耐心”。有一道Reverse题只给了一个64位的ELF文件,没有其他信息。我用strings命令看到一些关键词,比如/tmp/key、read()、flag.txt,猜测程序从/tmp/key读取一段数据,然后做异或操作后输出。
用Ghidra定位到主函数后,发现程序先读入16字节到栈缓冲区,接着用一个全局数组依次和这16字节做异或,最终数据去向是标准输出。我直接把全局数组的数据提取出来,写了个Python脚本跑一遍异或,就得到flag了。这里没有反调试、没有壳,属于纯逻辑转换题。但正是因为内部赛信息准确,反而比公开赛里那些“加了花指令又要动态调试”的题更友好。所以别看到Reverse就害怕,先静态分析,再动态验证,大多数题都能解决。
4. 踩坑记录与排查思路:都是我流过的血泪
4.1 环境问题:容器端口冲突和DNS解析
内部赛一般在线上比赛平台进行,每个题目分配一个动态容器。第一次参赛时,平台分配的Web容器地址可能是http://abc.node?ip=x.x.x.x&port=随机,但我的Burp配置了系统代理,有时会拦截到容器地址后无法正确访问,提示超时。排查发现是我本机hosts文件里残留了一些之前的测试IP映射,导致DNS解析走了旧的地址。
这类问题很常见,尤其是在切换不同赛题时。建议开赛前先关掉不必要的系统代理插件,或者把Burp设置为“只拦截指定工具”,避免代理规则干扰。另一个经典问题是本地已经启动的容器端口冲突:你本机的8080端口被某个用户进程占用了,赛题容器也是8080,但平台给的地址指向远端,不会冲突。如果是本地搭建的环境复现题目,务必先用lsof -i:8080检查端口占用。
4.2 工具误报:Burp的自动解压和编码转换
有一道题需要提交一段URL编码的data参数,我在Burp Repeater里看到的请求体是data=%7B%22name%22%3A%22admin%22%7D,正常发出去后端却一直报错。我以为是参数名不对,试了很多次,才发现是Burp已经把Content-Type设为application/x-www-form-urlencoded,并且自动帮我解码了%7B变成{。有些后端逻辑严格校验原始字符串,或者要求必须保留URL编码形式,这时就需要在Burp的“Hex”视图里直接修改,或者将Content-Type改为text/plain,让Burp不再做自动解码。
这个坑看起来很小,但在打题时浪费了我将近十五分钟。遇到类似“提交字符总被转义”的问题,先确认工具是否修改了熵值。
4.3 时间管理:卡题的时候该做什么
内部赛最短的只有两个小时,而CTF题目通常需要连续思考。我第一场内部赛在硬刚某道Pwn题时,反复进行栈调试和偏移计算,但怎么都拿不到shell,最后发现是远程libc版本和本地不同,需要先泄露libc再计算base地址,而我没有看到题目描述里已经标明“Ubuntu 18.04”。这就是典型的“审题不清”。
后来我给自己定了一个规矩:每道题最多投入25分钟,若没有实质进展就切到下一题,并记录当前尝试到哪一步。等到最后如果还有时间,再回来续接。这个方法的另一个好处是,换题后的“无意识灵感”经常能反过来让你重新理解上一道题。比如我在解一道Misc题时想到了某个代码混淆特征,回头再看Web题,才意识到它其实用了相同的编译混淆方式。
5. 赛后复盘:怎么让一次内部赛的收获翻倍
5.1 尽量保存现场数据
比赛结束时,平台上的容器通常会销毁,所以所有需要保存的数据必须在比赛中途就存下来。我自己的习惯是:每解一道题,都立刻把关键请求、响应包、脚本、flag提交后系统返回的提示截图,存到一个专门文件夹里。即使题目没解出,也要把已经掌握的线索、尝试过的payload、报错信息截图保存。
没有这些东西,赛后你只能靠记忆复盘,而记忆会很快模糊。有一次我赛后想复盘一道Reverse题,但当时没用Ghidra导出反编译代码,容器没了,什么都是空的,只能找题目描述回忆,效率极低。反过来,如果保存了prerequest和response,就能对照官方WP一步步看到自己的差距。
5.2 别人写的WP值得看的点
内部赛结束后,平台方或者社区里通常会流出一些高手的解题报告,这种“WP”(Writeup)非常宝贵。但看WP不是从头到尾抄一遍,而是带着问题看。我会重点看三个点:一是他们是怎么定位到漏洞入口的,跟我的思路差在哪;二是他们在绕过限制时选择的参数或编码方式,为什么我的尝试失败了;三是这个题目的命题意图,它想考察的知识点是什么。
比如前面说的那个Web题,官方WP里提到一个细节:登录接口其实还有一个debug=1参数,开启后会返回完整的后端异常栈,其中泄漏了服务器文件路径和使用的ORM框架。这个信息我完全没发现,只靠运气试出了base64伪造。如果当时能发现这个调试开关,解题时间会缩短一半。这种“信息差”只能通过复盘学到。
5.3 把踩坑沉淀成自己的检查清单
每次比赛结束,我会花二十分钟把这次的踩坑记录整理成一份个人版Checklist。比如“提交参数前先确认是否需要URL编码”“解压文件前先file查看类型”“连接题目容器前检查代理规则”等。这些条目会在我下一场比赛时作为快速排查指南使用。
别看这些清单很简单,关键时刻能救命。我第一次比赛时,因为忘记检查文件类型,把一个PNG图片当成普通文本处理,后来才发现文件头是PNG但文件尾附带了一个RAR压缩包,需要使用binwalk -e提取。这种事如果不在清单里,每次遇到都要重新试错。
我个人的体会是,参加ctfshow内部赛,与其说是为了排名,不如说是为了“以赛代练”。题目越是贴近实战,越能暴露出你平时学习中的盲区。而每一次赛后复盘,都是在给下一次比赛铺路。如果你也有机会参加类似的内部赛,一定要把“解题—记录—复盘—清单化”这个闭环跑完整,收获真的会比想象中大得多。