2026/10/10 9:41:20

CTF自动化脚本实战:Web与逆向双赛道提速指南及备赛路线

CTF自动化脚本实战:Web与逆向双赛道提速指南及备赛路线 2026年CTF赛季眨眼就到很多队伍从年初就在闷头刷题结果一打比赛还是手忙脚乱。我这两年带过几支学生队伍也在线上赛和线下赛里折腾了不少轮最大的感触是CTF拼的不是谁更拼命而是谁更会“偷懒”——这里的偷懒指的是用合理的脚本把重复劳动自动化把脑力留给真正的分析环节。这篇东西不聊虚拟机的配置也不说怎么搭实验环境就讲两个我实测下来最顺手的自动化脚本一个偏Web一个偏逆向加上一条分阶段路线和适合多数人的赛事筛选逻辑想少走弯路的可以直接参照。先说清楚一个前提脚本不是外挂更不是能一键拿分的核弹。CTF题目是搭建在虚拟靶场里的你本机跑的脚本再怎么花哨也只会作用于赛场上的模拟目标。写好脚本的本质是为自己节省手动请求、批量改参数、反复解码这类耗时步骤让解题节奏更快仅此而已。下面我按脚本思路、落地细节、路线规划、赛事推进四个维度展开最后附上我踩过的坑和当下觉得最重要的心得。1. 2026年CTF比赛节奏与备赛心态1.1 赛季时间线怎么看很多人把“CTF赛季”理解成一年365天都在打比赛实际上真正性价比高的比赛集中在上半年和下半年各一波。上半年以综合类赛题为主适合新人练手下半年偏向深度和实际业务场景适合有一定基础的老手冲击奖项。我这里说的2026年节奏是从2025年底开始准备到2026年11月收尾的一个完整循环。以我自己的观察2026年的题目风格会继续往“真实业务环境”靠拢。Web题不光是给个注入点让你拼SQL而是更像一套完整的订单系统你得先从路由里找到参数再一步步构造链路逆向题也不只是简单的flag校验而是加入了很多系统保护机制需要你从动态调试里捞关键变量。这种变化意味着手敲命令的时代正在过去批量验证、自动抽取、快速对比的脚本能力越来越重要。如果从零开始我的建议是别急着打比赛先用三个月刷够基础题等题目见得多了再开始“以赛代练”。每年的3月到6月是黄金练习期很多入门级比赛在安排赛题时会有意识降低难度这段时间用来验证脚本流程非常合适。7月到8月是沉淀期别安排太密集的比赛把之前遇到的杂七杂八问题统一清理掉。9月到11月可以冲一批更有含金量的赛事这时候你的脚本库和模板基本成型比拼的就是临场发挥了。1.2 新手最容易犯的三个错第一个错是“只学不练练了不背”。CTF的题虽然千奇百怪但每个类别的高频考点是有限的。比如Web方向信息泄露、上传绕过、反序列化这几类反反复复出现。逆向方向带壳的、无壳的、混淆的也各有套路。光看教程不练过两周全忘练了不把对应解题流程沉淀成脚本下次还是从零开始敲效率极低。第二个错是“打开一堆工具但不知道工具在处理什么”。很多新人打开工具界面就蒙了左边一个插件右边一个面板全看懂了但就是不知道下一步点哪。其实工具底层就是发送请求、解析响应、处理二进制。如果你先明白这个本质再去看任何工具都会很快。写脚本也一样本质是把自己对协议和数据的理解固化成代码而不是依赖某个图形化工具。第三个错是“不尊重比赛环境瞎搞自动化”。这里特别提醒CTF平台会有保护机制比如请求频率限制、token验证、动态flag轮换。脚本设计时必须考虑这些不然刚跑两下就被封IP甚至影响整队成绩。我看到太多队伍在比赛里被自己的脚本坑死所以要清醒地认知到自动化脚本首要目标是稳定其次才是速度。2. 两条实战自动化脚本到底解决什么问题2.1 Web方向的脚本不是漏洞枪而是分级加速器很多人在CTF里用了大量时间做同一件事读源码、找参数、构造请求。一套正常的Web解题流程里真正需要脑子的部分是“判断这里该用什么协议、传什么参数、期待什么响应”。但判断完之后具体发多少次包、怎么改排列组合、怎么用二分法找flag字段这些都是体力活。体力活交给脚本判断留给人脑这是Web方向脚本的核心定位。我用的Web脚本本质上是一个“请求模板转发器”。它允许我定义一个基础URL、一组参数模板、一组替换变量然后自动做排列组合把不同响应保存下来。听起来很简单但在实际比赛里这种简单脚本能救大命。比如你面对一个需要逐字符探测的flag比较逻辑手工一次只能试一个字符脚本可以自动循环把响应中的时间差或长度差变成彩色打印几百次请求几秒钟就完事。这个脚本另一个价值是“结果归一化”。每个题目的响应格式不一样有的返回JSON有的返回纯文本有的夹在HTML里。脚本会把我关心的部分抽出来统一打印成“状态码、响应体、耗时”三列这样我就能快速对比不同输入下的差异找到可疑点。有了它我再也不会一题一题地写临时脚本而是直接在框架里套模板。2.2 逆向方向的脚本让重复劳动滚出解题流程逆向题最耗时间的部分往往不是分析逻辑而是处理二进制里的各种编码和加密片段。遇到一个程序你先要识别有哪些字符串、哪些函数、哪些调用关系然后从中找到flag生成的线索。人工去逐个字符串翻真的很崩溃。我总结了一套逆向辅助脚本专门做三件事提取、变换、对比。提取就是扫描二进制文件里的可打印字符串包括UTF-8、宽字节、ASCII甚至隐藏在资源段的片段。变换就是对你输入的各种候选值做常见编码和哈希处理比如Base64、Hex、MD5、RC4之类。对比则是把变换后的结果和目标字符串做相似度匹配找出最像的那几个缩小人工分析范围。这套脚本最大的价值不是自动得到flag而是帮我把“看似无关的字符串”和“目标flag格式”通过变换拉上关系。很多逆向题会故意把flag拆成几段分散在加密函数里手工找全都要小心翼翼。脚本里加一个自动收集交叉引用的功能就能把有关联的地址全列出来再配合反汇编结果很快就能定位关键部分。简单说把逆向里那些“找来找去”的工作压缩到一两分钟内让你把时间花在真正的算法分析上。3. Web方向脚本设计与落地实录3.1 设计目标和代码框架在动手写脚本前我先定了几个目标第一它必须能在不同比赛里复用而不是每次重写第二它必须支持HTTP和HTTPS的所有方法能自定义请求头第三它要能对响应做规则化提取方便比较。基于这些目标我选择用Python做主语言配合几个常用库整个脚本被我拆成四个模块。请求引擎模块负责发送请求、处理代理、超时重试。模板解析模块读取题目给定的请求模板替换其中变量。响应提取模块用正则或XPath从响应中提出指定字段。统计输出模块把每次请求的状态、耗时、响应摘要按行输出到屏幕和日志文件。这里特别说一下为什么要单独拆响应提取模块。CTF里同一个参数往往要试很多次响应差异可能很小比如只有某个字符不同如果直接打印全部响应体你看半天看不出区别。提取模块里我会定义“关注点”比如提取响应头中的Set-Cookie、提取响应体中和“flag”相关的字符、提取时间字段。这样输出非常干净人眼一扫就能发现异常。代码框架不算复杂但真正写好需要打磨。我最初版本把所有逻辑堆在一个文件里一换题就修后来按模块拆开才顺手。下面是请求引擎模块的一个核心片段它做的事情很简单循环请求一段URL自动处理重定向和Cookie并把每次响应时间记录下来。这段代码可以直接复制到你的脚本里当底子。import requests import time from urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) def send_request(url, methodGET, paramsNone, headersNone, cookiesNone, allow_redirectsTrue, timeout8): start time.time() try: if method.upper() GET: resp requests.get(url, paramsparams, headersheaders, cookiescookies, allow_redirectsallow_redirects, timeouttimeout, verifyFalse) elif method.upper() POST: resp requests.post(url, dataparams or {}, headersheaders, cookiescookies, allow_redirectsallow_redirects, timeouttimeout, verifyFalse) elif method.upper() PUT: resp requests.put(url, dataparams or {}, headersheaders, cookiescookies, allow_redirectsallow_redirects, timeouttimeout, verifyFalse) else: resp requests.options(url, headersheaders, timeouttimeout, verifyFalse) elapsed round((time.time() - start) * 1000, 2) return { status: resp.status_code, headers: dict(resp.headers), body: resp.text, elapsed_ms: elapsed } except Exception as e: return {status: 0, headers: {}, body: str(e), elapsed_ms: 0}注意verifyFalse是为了应对比赛环境中常见的自签名证书如果你在真实生产环境跑请一定保持verifyTrue不要照抄这个参数。3.2 关键模块拆解请求模板、特征识别、Flag自动提取请求模板是这个脚本里最灵活的部分。我在比赛里拿到一道题先手工跑通一两个请求然后把请求的URL、请求头、参数结构抽成模板。模板里用{{和}}包住可变部分比如{{id}}、{{page}}、{{token}}。脚本读取模板后按组合规则生成一批实际请求。比如我想测试id从1到100的变化脚本会自动替换并依次请求而不是要求我手动复制一百次。特征识别是让脚本“有点聪明”的设计。我常在响应里找两类标志一类是明显的关键词比如“flag{”“Error”“Success”另一类是数值型变化比如响应长度或时间差。脚本会把这两类特征单独标成高亮并且自动计算前后两次请求的差异。如果差异仅出现在某次特定请求中就立刻把这次请求的参数组合打印出来。这个过程大大加快了我的判断速度。flag自动提取是我最喜欢的功能。不管响应是HTML还是JSON我总是把提取规则写成正则。比如响应里出现的形式是“flagxxxxxx”那我直接用一个通用正则把匹配到的内容放进一个变量后续所有请求都会带上这个变量相当于自动把上一轮的结果传给下一轮。这样处理多步交互类题目时我只需要在初始模板里定义第一次请求后续脚本会自动维持会话状态。下面这段代码展示了响应提取和差异标记的核心逻辑它把响应长度、请求耗时、命中关键词三类特征做了一次聚合输出成易读的表格文本。import re from tabulate import tabulate def extract_features(label, resp, keywords(flag{, success)): body resp.get(body, ) length len(body) elapsed resp.get(elapsed_ms, 0) hit [kw for kw in keywords if kw in body.lower()] return [label, resp.get(status), length, elapsed, |.join(hit) if hit else -] def run_template(template, cases): rows [] for case in cases: url template[url].replace({{param}}, str(case)) resp send_request(url, methodtemplate[method]) rows.append(extract_features(str(case), resp)) print(tabulate(rows, headers[case, status, length, elapsed, hit], tablefmtgrid)) # 示例模板 template {url: http://靶机地址/index.php?id{{param}}, method: GET} cases range(1, 10) run_template(template, cases)实际比赛里我还会在模板里加一个“登录后封装”步骤把带token的Cookie存到一个会话对象中后续请求全部复用。这是必须的因为很多题目的关键接口藏在登录之后如果每轮请求都得手动复制登录态脚本优势就没了一半。3.3 脚本的坑与调试心得第一个坑是“会话保持失效”。很多网站会检查Cookie的时效你上一秒还在用的会话下一秒就过期了。我一开始给脚本设置30秒超时后来发现有的平台Cookie有效期只有15秒于是改成每次请求前先验证Cookie过期就自动重新登录。这个逻辑说起来简单但做的时候要注意别把重新登录的请求也纳入测试数据否则输出会非常混乱。第二个坑是“频率限制”。CTF平台的防护不像生产环境那么强但有些活动题目会做简单限速。刚开始我的脚本用多线程并发速度上去了结果打了不到两百个请求就被平台封禁了几分钟。后来我把线程数改成3个每次请求间隔0.2秒基本就不会触发限制。你要根据题目环境的“温和程度”调整节奏别上来就全速跑。第三个坑是“输出信息过载”。如果一个请求的响应体有几万字符你把所有内容都打印到控制台再找差异眼睛就废了。我后来加了一个自动摘要功能默认只打印前200个字符和最后100个字符中间用省略号代替同时高亮命中的关键词。这样既能看到开头和结尾的关健信息又不会刷屏。这个小改动让我的调试效率提高了不少。调试脚本本身也有一些技巧。我习惯在脚本里加一个debug开关开起来后会打印完整请求报文和响应头。遇到题目怎么都跑不通时开着debug对比手工请求和脚本请求的差异一眼就能看出是不是漏了某个Header。还有一点脚本运行结束后我会把整个过程的所有请求和响应存到本地文件这样复盘时能准确记得自己试过什么不至于“赛后失忆”。4. 逆向方向脚本设计与落地实录4.1 脚本要覆盖的逆向高频场景逆向题的输入是一个二进制文件可能是一个可执行程序也可能是一个动态库。大部分情况下我需要先搞明白程序输出了什么、哪些函数是入口、哪些函数负责处理flag。脚本覆盖面不宜太广应该集中在四个高频场景上字符串提取与筛选从二进制里找出所有可打印字符串并按长度、是否包含flag、是否出现在特定段进行过滤。编码识别与转换自动尝试Base64、URL编码、十六进制、ROT13等常见变换并和已知目标做对比。交叉引用收集找出哪些地址引用了某个关键字符串或数值帮助缩小分析范围。加密算法探测通过字节模式匹配识别常见的加密函数特征比如AES的S盒、RC4的初始化逻辑。这四个场景做齐基本覆盖了六成以上的逆向题。剩下的难题可能需要手撸算法不是脚本能解决的但脚本至少能帮你快速排除掉简单的可能。4.2 核心代码思路字符串提取、加密识别、自动替换字符串提取是所有逆向分析的起点。我用Python来遍历二进制文件里的每个字节按ASCII或Unicode的模式组成连续字符串然后过滤掉长度小于4的。同时可以传入过滤正则只留包含特定关键字的项。这个脚本比我手动在反汇编软件里一个个找要快很多尤其是处理带压缩或加壳的程序时它能先提取一层壳外的字符串再配合脱壳后的二次提取做对比。自动替换是我觉得最讨巧的功能。很多逆向题会把flag拆成几个部分分别加密后再拼接。我设计了一个“互替换”机制给定两个候选字符串列表脚本会将它们逐一组合并计算组合后字符串的哈希或编码结果然后对照题目给定的目标值。一旦匹配成功说明找对了组合顺序。这个过程就是穷举加对比在可接受的字符集和长度范围内非常有效。加密识别部分我实现了一个轻量级的“字节模式匹配器”。比如RC4初始化时有经典的S盒置换循环AES加密有固定的查找表这些特征在二进制里是存在的。脚本通过特征码定位到这些函数然后在反汇编软件中跳转到对应地址进行人工分析。不过这个功能需要你有一定的二进制底子如果你暂时用不上也不用强求先把字符串提取和编码转换用熟就已经能解决很多简单题目了。4.3 运行效果与边界说明跑通这份脚本后的直观感受是逆向题的“找”过程明显变快了。以前一个常规题目我可能要花20分钟在反汇编里翻字符串现在30秒内就能得到一份分类好的候选清单然后直接聚焦到可疑函数。配合动态调试器很多题目从拿到文件到定位关键校验点能压缩到10分钟以内这给后续的分析和赛题提交留出了充足时间。但这套脚本不是万能的。碰到强混淆或自定义加密算法的题目脚本提取到的字符串可能全是假的自动替换也会因为目标格式不明而失效。这时候别硬刚脚本老老实实开调试器逐步分析才是正道。我的经验是脚本负责“广撒网”人工负责“精分析”。你越早接受这个边界越能合理分配时间。另一个要注意的是脚本本身的运行效率。扫描一个几十MB的二进制文件如果用单线程加上特征匹配可能会卡住一两分钟。我后来加了一个进步条和分段扫描功能把文件按大小切成若干块并行处理耗时能缩短一半。但并行要做好内存控制不然机器配置一般的话容易直接内存溢出。5. 分阶段路线规划从入门到站上领奖台5.1 阶段一形成对抗性思维第1-3个月第一阶段的目标不是拿奖而是建立一个“题目是怎么设计出来”的基本感觉。这三个月我建议只做两件事刷基础题复盘别人的解题思路。基础题指的是单个考点清晰的题目比如只考察一个XSS、只考察一个简单的二进制算法。别碰综合题不然很容易产生挫败感。每周给自己定一个主题比如第一周专门看SQL注入第二周专门看XSS第三周专门看PHP反序列化。这个阶段可以不太依赖脚本先把工具操作练熟知道每个功能对应的是什么处理过程。比如你在BurpSuite里改了一个请求头你脑子里要很清楚这个改动实际产生的影响是什么。如果你能用原始请求工具完成一个完整解题流程再把这个流程转成脚本你就算是真正理解了原理。本轮复盘时建议把每道题的核心考点和解题链路记录成一张卡。我在这个阶段使用的记录模板很简单题目名称虚拟、涉及知识点、手工操作步骤、脚本化可能性、耗时。月底翻看这些卡你会惊讶地发现同类型题解题链路高度相似。5.2 阶段二主攻一个赛道4-9个月第四个月开始必须选定自己的主赛道。别贪心一个人同时精通Web和逆向很难两个都半吊子不如一个能打。选赛道依据不是兴趣而是你的技术背景如果你对HTTP协议和网络栈熟悉选Web如果你对汇编和操作系统熟悉选逆向。选定后主赛道占比至少百分之七十剩下的时间用来了解其他赛道的高频思路防止遇到“混合题”时完全看不懂。这个阶段也是你脚本能力飞速提升的时期。你会在阶段一记录的卡片里发现有些操作重复度极高比如批量请求、自动提取、字符串搜索。把这些操作用脚本实现并逐步迭代成可复用模块。这期间的脚本不用追求完美能解决当前问题就好但记得写注释和保存版本不然下个比赛又找不到原来的代码了。在主赛道深入挖掘的同时我建议每个月参加一场线上入门赛一来检验水平二来保持比赛状态。比赛复盘非常关键哪怕排名靠后也要把每道你觉得“差一点就做出来”的题重新写一遍解题脚本。把比赛里遇到的问题变成下一周的学习目标这是进步最快的方式。5.3 阶段三打比赛、复盘、体系化10-12个月到了十月路线规划的重点从“学新知识”转到“打磨效率”。这个阶段需要你完整跑几套系列赛拿到题目后按照“识别考点→调用脚本→人工分析→提交flag”的标准流程操作。你要给自己设置一个时间预算比如Web题最多50分钟逆向题最多60分钟。超过预算果断放弃做下一题别在一道题上死磕。复盘时我强烈建议做一个“误判集”。记录这次比赛中哪些地方你判断错了是漏了某个响应头还是对一个函数的作用理解偏差。脚本也可以和误判集挂钩比如我上次因为没考虑时间盲注漏掉了基于延时的flag后来在脚本里加了一个“延时检测”特性。脚本体系就是这样一点点丰满起来的。赛季末尾把你的所有脚本整理成一个命令工具统一入口、统一参数。平时练习也强制用这个工具不要回了家又手搓。这样你在比赛现场才能闭着眼睛快速调用减少临场出错概率。拥有自己的自动化工具箱这比多背几个库函数重要得多。6. 全年赛事表与选赛策略6.1 按时间分布的关键比赛节点我依据2026年赛季的一般规律整理出下面这张备赛时间表。注意比赛名称是泛指类型不特指某个具体组织方因为实际赛事的发布时间经常调整所以更重要的是把握比赛节奏。时间段比赛类型适合人群备赛重点2月-3月入门综合赛新手熟悉比赛流程和平台操作4月-5月Web方向专题赛Web选手验证自己的Web脚本模板6月逆向方向专题赛逆向选手验证提取和变换脚本7月-8月暑期休整期老手集中修复脚本bug整理模板库9月-10月综合高手赛进阶选手查漏补缺模拟赛时压力11月-12月年底总决赛全阶段检验全年训练成果这张表只是个参考框架。真实世界里的CTF比赛常有冲突同一个月好几个赛事撞车你需要根据自己的主赛道和状态选择一两个重点参与而不是全部报名。全程高负荷参赛只会消耗你的精力反而影响成绩。6.2 选赛的五个原则第一优先选“赛题会公开”的比赛。赛后能拿到原题和官方解析这样无论排名如何你都有足够的学习素材。若是那种答完就锁的赛题复盘价值大打折扣。第二优先选“难度分层清晰”的比赛。好的赛事会有新手题、中等题、难题三个梯度确保你在不同水平阶段都能找到适合自己的题目。如果一场比赛全是难题新手参加只会打击自信。第三优先选“队伍人数合理”的比赛。3-4人是比较理想的CTF战队规模。人数太少Web和逆向同时出的题目顾不过来人数太多沟通成本太高脚本和知识也难以统一管理。第四优先选“支持动态flag”的比赛。这类比赛能有效避免“抄答案”行为对认真做题的人更公平也能在一定程度上保护你已经写好的脚本模板不受别人的flag干扰。第五也是最重要的——优先选择“和你水平匹配”的比赛。别看到高分队就去鉆牛角尖找一个你踮踮脚能碰到的名次就行。这样压力适度成长也快。7. 避雷清单与个人心得7.1 实战中最容易被忽略的“隐形扣分项”我参加过不少CTF很多队伍包括我们自己都曾败在非常低级的问题上。最常见的是提交flag格式错误。有些题目明确要求flag包括某种前缀脚本提取时如果不小心把多余空格或换行带进去提交必失败。所以我给脚本加了一个自动清洗函数把提取到的flag统一去除空白字符并和已知格式做正则校验不匹配就不提交。另一个隐形扣分项是环境依赖没装齐。比赛现场的机器可能没有你本机配置好的各种库或者版本不一致。靠谱的队伍会在赛前把常用环境整理成一套自动化脚本一键安装固定版本的工具和依赖库。这虽然不是“解题脚本”但同样是自动化能力的体现。还有就是“日志缺失”。线上赛持续48小时你会忘记自己在第20小时做了什么推测。如果你没有把请求和响应记录下来后面根本没法复盘。我现在不管跑任何脚本都会强制输出一份带时间戳的文本日志赛后按时间线检查当时的思路走向能发现很多不必要的弯路。7.2 让脚本帮你沉淀知识最后聊点个人体会。很多人觉得写脚本是为了比赛拿分但我更觉得它是知识沉淀的一种方式。每当我为一个问题写了新的脚本模块我会顺带更新一下自己的笔记记录下“为什么需要这个模块、它对应哪一类题目、还有哪些变体没覆盖”。半年下来这套笔记就成了我独一无二的CTF手册。CTF这个圈子真正拉开差距的不是记忆力而是你把经验转化为工具的能力。我见过有人把大量时间花在收藏各类文章上但比赛时照样脑袋空空也见过有人只写了几个很简单的脚本但每个脚本都能精准切中某类题目的关键环节。我希望你读完这篇内容后不要就去网上找autopwn一键脚本。老老实实从自己的解题过程里提炼需求写出属于你的自动化工具那才是2026赛季最稳的不会让你后悔的投入。