1. 当AI开始自己打比赛人类选手还剩下什么前阵子我把一套自动化解题流程完整跑通之后盯着屏幕上自动弹出的flag脑子里冒出来的第一个念头就是标题里那句话——已经没有人类了。这不是在贩卖焦虑而是我在实际搭建和调试这套东西的过程中真真切切感受到的一种冲击。你想想看一个CTF题目扔过来从信息收集、漏洞识别、payload构造到最终拿到flag整个链路没有我手动敲过一行命令全是自动化流程在跑这种感觉确实挺魔幻的。这篇文章想聊的就是我最近折腾的一套AI全自动打CTF的解题记录。CTFCapture The Flag是网络安全领域常见的竞赛形式题目涵盖Web渗透、逆向工程、密码学、杂项分析、二进制漏洞利用等方向。传统打法是人盯着题目手动分析、手动写脚本、手动提交flag。而我这套方案的核心思路是让大语言模型充当大脑配合工具链和自动化调度框架实现从题目解析到flag提取的全流程闭环。适合谁来读这篇东西如果你是对CTF感兴趣但刚入门的新手可以看看自动化思路能帮你省掉哪些重复劳动如果你是有一定经验的老选手可以关注工具链编排和提示词工程那部分这些是我踩了不少坑才调通的如果你纯粹是对AI自动化感兴趣那这套架构思路其实可以迁移到很多其他场景比如自动化代码审计、自动化漏洞挖掘等等。需要提前说明的是整套方案目前还远没到完全替代人类的程度标题里的已经没有人类了更多是一种夸张的表达。实际跑下来简单题和中等难度的题目自动化成功率还不错但遇到需要深度推理或者非常规思路的题目AI还是会卡壳。不过光是能在部分场景下实现全自动解题这件事本身就值得记录一下了。2. 整体架构设计与核心思路拆解2.1 为什么选择LLM工具链调度器三层架构一开始我尝试过最简单的方案直接把题目描述扔给大语言模型让它直接给出答案或者flag。实测下来这种方式在密码学方向的一些简单编码题上偶尔能蒙对但稍微复杂一点就完全不行了。原因很简单大语言模型本质上是一个文本生成模型它没有真正的执行能力——你让它算一个RSA解密它可能在推理过程中算错你让它分析一个二进制文件它根本看不到文件内容。所以我最终确定的架构是三层最上层是决策层由大语言模型负责它的角色是指挥官负责理解题目意图、制定解题策略、决定下一步调用什么工具中间层是工具层包括各种命令行工具、Python脚本、自定义的辅助程序负责实际执行具体操作最底层是调度层负责管理整个流程的状态、处理工具返回结果、决定是否继续迭代还是终止。这个架构的核心逻辑其实和人类解题的过程很像。人类选手看到一个Web题目先判断可能是SQL注入还是文件包含然后打开浏览器或者Burp抓包测试根据返回结果调整payload反复尝试直到拿到flag。AI自动化要做的就是把这个过程拆解成可编程的步骤让LLM在每个决策点做出选择工具负责执行调度器负责串联。注意不要试图让LLM一次性完成所有推理。我最初的错误就是给了一个超长的prompt试图让模型从头到尾给出完整解题步骤。结果模型在中间步骤就开始产生幻觉后面的步骤全建立在错误的前提上。正确做法是把解题过程拆成多个小步骤每一步只让模型做一个决策拿到工具返回结果后再进行下一步。2.2 工具选型背后的考量工具层的选择直接决定了整套系统的能力上限。我最终选用的工具组合是这样的工具类别具体工具用途选择理由网络交互命令行HTTP客户端Web题目请求发送与响应分析轻量、可脚本化、输出格式统一编解码Python标准库自定义脚本各类编码转换、哈希计算灵活度高可覆盖绝大多数编码场景逆向分析反汇编工具字符串提取工具二进制题目静态分析命令行友好输出可被LLM理解密码学自定义Python脚本集RSA、AES、古典密码等针对CTF常见题型定制文件分析文件类型识别工具十六进制查看器杂项题目文件分析快速定位文件真实类型和隐藏信息这里有一个关键的设计决策所有工具的输出格式必须统一且结构化。为什么因为LLM需要理解工具返回的结果才能做出下一步决策。如果工具输出是一大堆乱七八糟的日志模型很容易迷失在信息里。我的做法是让每个工具的输出都经过一层格式化处理提取关键信息用简洁的JSON或者固定格式的文本返回给决策层。举个例子Web题目发送HTTP请求后原始响应可能包含大量HTML、CSS、JavaScript代码。如果直接把整个响应扔给LLMtoken消耗巨大不说模型还可能被无关信息干扰。我的处理方式是提取状态码、响应头中的关键字段、响应体中的可疑字符串比如flag格式的字符串、报错信息、数据库相关关键词然后把这些精简后的信息传给模型。2.3 调度器的状态管理机制调度器是整个系统的中枢神经它需要维护一个状态机记录当前解题进行到哪一步、已经尝试过哪些方法、哪些方法失败了、下一步应该尝试什么。我设计的状态包括初始化状态接收题目信息进行初步分类信息收集状态调用工具收集题目相关的基础信息策略选择状态根据收集到的信息让LLM决定解题方向执行状态调用具体工具执行操作结果评估状态判断执行结果是否有效是否接近目标终止状态成功拿到flag或者达到最大尝试次数状态之间的转换由LLM的决策和工具的执行结果共同驱动。这里有个很重要的设计原则设置最大迭代次数和超时机制。我一开始没有设限制结果遇到一道解不出来的题目系统在那里反复尝试了几十次浪费了大量token和时间。后来我设置了最大迭代次数为15次超过就自动终止并输出未能自动解决的结论。3. 核心模块拆解与实操要点3.1 题目分类模块的实现细节题目分类是整个流程的第一步也是最关键的一步。分类错了后面的工具调用和策略选择全都会跑偏。我的做法是结合题目描述文本和附件文件特征进行综合判断。对于文本描述我会提取关键词比如出现SQL、注入、数据库等词汇就初步判断为Web方向出现加密、密文、密钥等词汇就判断为密码学方向出现逆向、汇编、二进制等词汇就判断为逆向方向。但光靠关键词不够准确因为有些题目描述故意写得模糊。所以我还加入了附件文件分析。如果附件是一个可执行文件那大概率是逆向或者PWN方向如果附件是一堆文本和加密脚本那大概率是密码学方向如果附件是图片、音频、压缩包那可能是杂项方向。文件类型识别我用的是文件头签名比对的方式读取文件的前几个字节对照常见的文件签名表来判断真实类型。实操心得有些CTF题目会故意修改文件扩展名来迷惑选手比如把一个PNG图片命名为data.txt。所以千万不要只看扩展名一定要读取文件头来判断真实类型。我在系统里专门加了一个文件类型校正的步骤实测下来避免了好几次误判。分类模块的输出是一个结构化的分类结果包含方向标签和置信度。如果置信度低于某个阈值系统会同时尝试多个方向的解题策略而不是死磕一个方向。3.2 提示词工程让LLM做出靠谱的决策提示词的质量直接决定了LLM决策的准确性。我在这上面花了大量时间反复调试总结出几个关键原则。第一个原则是角色设定要具体。不要只说你是一个网络安全专家而要更具体地描述它的职责和约束。比如我用的角色设定是你是一个CTF自动化解题系统的决策模块你的任务是根据当前收集到的信息选择下一步应该执行的操作。你只能从给定的操作列表中选择不要尝试自己编造操作。如果你认为当前信息不足以做出决策选择继续收集信息操作。第二个原则是输出格式要严格约束。我要求LLM的输出必须是JSON格式包含action、parameters、reasoning三个字段。action指定要调用的工具parameters是传给工具的参数reasoning是决策理由。这样调度器可以直接解析JSON来执行操作不需要再做额外的自然语言理解。第三个原则是提供充分的上下文。每次调用LLM时我会把题目描述、已收集的信息、已尝试过的操作和结果都作为上下文传进去。这样模型不会重复尝试已经失败的方法也能基于历史信息做出更合理的决策。# 提示词模板示例简化版 prompt_template 当前题目信息 {challenge_info} 已尝试的操作及结果 {history} 可用的操作列表 {available_actions} 请根据以上信息选择下一步操作。输出格式为JSON {{action: 操作名称, parameters: {{...}}, reasoning: 决策理由}} 这里有个坑要注意上下文不能无限增长。随着解题步骤增多history会越来越长最终可能超出模型的上下文窗口限制。我的处理方式是只保留最近N步的历史记录更早的记录压缩成摘要形式。3.3 工具调用的安全边界与异常处理自动化系统调用工具时必须考虑安全边界。比如Web题目中自动化脚本可能会发送大量请求如果不加限制可能对目标服务器造成压力甚至触发防护机制导致IP被封。我在系统里加了几个限制请求频率限制每秒最多发送3个请求总请求数限制单个题目最多发送200个请求超时设置每个请求最多等待10秒异常重试请求失败时最多重试2次之后放弃该路径异常处理也是重点。工具执行过程中可能遇到各种意外情况命令不存在、权限不足、输出格式不符合预期、程序崩溃等等。我的做法是给每个工具调用都包一层try-catch捕获异常后把错误信息返回给调度器由调度器决定是重试、换方法还是终止。注意千万不要让自动化系统在没有限制的情况下运行。我最初测试时没有加请求频率限制结果一道Web题目跑下来发了上千个请求直接把测试环境的服务打挂了。后来加了限制才稳定下来。4. 完整解题流程实录与关键环节4.1 一道Web题目的全自动解题过程我拿一道典型的Web题目来完整演示整个流程。题目描述是目标站点有一个登录页面尝试获取管理员权限并找到flag。附件无只给了一个URL。系统启动后首先进入题目分类模块。根据描述中的登录页面、管理员权限等关键词分类为Web方向置信度0.92。然后进入信息收集状态。第一步调度器调用HTTP请求工具发送GET请求到目标URL。工具返回状态码200响应体是一个登录页面的HTML。格式化模块提取了页面中的表单字段username、password、引用的JavaScript文件路径、以及页面注释中的一条提示信息。第二步LLM根据收集到的信息做出决策。它注意到页面注释中有一条提示 。模型判断这可能是一个备份文件泄露漏洞决定尝试下载该文件。调度器调用HTTP请求工具下载/backup.zip成功获取到一个压缩包。第三步系统自动解压备份文件发现里面包含网站源代码。LLM分析源代码后发现登录逻辑中存在SQL注入漏洞并且注释中透露了数据库表结构。模型决定构造SQL注入payload尝试绕过登录。第四步调度器调用HTTP请求工具发送带有注入payload的POST请求。工具返回状态码302响应头中Location字段指向/admin.php。模型判断注入成功决定访问/admin.php。第五步访问admin.php后页面中直接显示了flag。系统提取flag并验证格式确认无误后终止流程。整个过程从开始到拿到flag耗时约47秒共进行了5轮LLM决策调用了12次工具。这个效率比我自己手动做要快不少尤其是信息收集和代码分析环节自动化确实省事。4.2 一道密码学题目的自动化尝试再来看一道密码学题目。题目给了一个Python加密脚本和一段密文要求解密获取flag。加密脚本的逻辑是将flag的每个字符转换为ASCII码然后进行一系列数学运算最终输出一串数字。密文就是这串数字。系统分类为密码学方向后首先调用文件分析工具读取加密脚本内容。LLM分析脚本后理解了加密逻辑决定编写解密脚本。这里有一个关键点LLM需要自己写出解密代码。我的系统里集成了一个Python代码执行工具LLM生成的代码会直接在这个工具里运行。LLM生成的解密脚本第一次运行失败了报错显示数组越界。调度器把错误信息返回给LLMLLM分析后发现自己对加密逻辑的理解有偏差修正后重新生成脚本。第二次运行成功输出了flag。这道题总共进行了3轮LLM决策调用了5次工具耗时约23秒。值得注意的是LLM在第一次失败后能够根据错误信息自我修正这个能力在自动化解题中非常关键。4.3 一道逆向题目的自动化挑战逆向题目是自动化难度最高的方向之一。我测试的这道题给了一个二进制可执行文件要求找到正确的输入使程序输出Correct。系统首先调用文件类型识别工具确认这是一个ELF格式的可执行文件。然后调用字符串提取工具提取出文件中的可打印字符串。LLM分析字符串后发现了一些可疑的字符串比如Wrong、Correct、以及一段看起来像base64编码的字符串。模型决定先尝试解码那段base64字符串解码后得到了一段有意义的文本但并不是flag。然后模型决定调用反汇编工具对二进制文件进行反汇编分析。反汇编输出非常长格式化模块提取了关键函数main函数、比较函数的汇编代码传给LLM分析。LLM分析汇编代码后理解了程序的校验逻辑它把用户输入经过一系列变换后与一个硬编码的字符串比较。模型根据汇编逻辑反推出了正确的输入然后调用程序执行工具输入该字符串程序输出Correct但flag并没有直接显示。这时候模型有点卡住了。它尝试了几种方法都没有找到flag。最终系统在达到最大迭代次数后终止输出未能自动解决。这道题暴露了当前方案的局限性当flag不是直接输出而是需要进一步操作比如把正确输入提交到远程服务器时自动化系统缺乏对题目整体意图的理解能力。人类选手可能会想到这个输入可能需要提交到某个地方但LLM在没有明确提示的情况下很难做出这种跳跃。5. 常见问题与排查技巧实录5.1 LLM决策陷入死循环怎么办这是最常见的问题之一。LLM在某个步骤反复选择同一个操作即使该操作已经失败过多次。比如它一直尝试用同一个payload注入即使每次都返回失败。我的解决方案是在提示词中加入已尝试操作的明确提示并且在调度器层面设置同一操作连续失败3次则强制跳过的规则。另外我还会在提示词中加一句如果你发现某个操作已经尝试过且失败请不要重复选择尝试其他方法。实测下来加了这些约束后死循环的概率大幅降低。但偶尔还是会出现所以调度器的强制跳过机制是最后的兜底。5.2 工具输出格式不符合预期怎么处理工具的输出格式可能会因为环境差异、版本不同等原因发生变化。比如某个工具在你的机器上输出JSON在另一台机器上可能输出纯文本。我的做法是在格式化模块中加入容错处理。首先尝试按预期格式解析如果失败则尝试备用解析方式再失败则把原始输出截断后直接传给LLM让模型自己理解。同时系统会记录格式解析失败的次数如果某个工具的失败率过高就提示需要检查工具配置。5.3 如何判断flag是否正确CTF的flag通常有固定格式比如flag{...}或者CTF{...}。我在系统里加了一个flag格式校验模块用正则表达式匹配常见的flag格式。如果提取到的字符串符合格式就认为是有效flag如果不符合则继续尝试。但有些比赛的flag格式比较特殊所以这个校验模块需要根据具体比赛规则进行调整。我的建议是至少支持3-5种常见格式并且允许手动配置自定义格式。5.4 常见问题速查表问题现象可能原因排查方法解决方案LLM反复选择同一操作提示词缺少历史信息检查history是否传入加入已尝试操作提示强制跳过规则工具调用超时网络问题或目标无响应检查网络连接和目标状态设置超时重试机制flag格式不匹配flag格式配置错误检查正则表达式更新flag格式配置分类错误关键词提取不准确检查题目描述和文件特征调整分类阈值多方向尝试token消耗过大上下文过长检查history长度压缩历史记录限制上下文窗口5.5 几个容易被忽略的实操细节第一个细节是文件编码问题。有些CTF题目附件的文本文件可能使用非UTF-8编码直接读取会乱码。我在文件读取工具里加了编码自动检测尝试多种常见编码直到找到能正确解码的。第二个细节是命令注入风险。虽然是在自己的环境里跑但如果LLM生成的命令中包含特殊字符可能会导致意外执行。我在工具调用层加了参数转义和命令白名单机制只允许执行预定义的安全命令。第三个细节是日志记录。自动化系统跑起来之后如果没有详细的日志出了问题很难排查。我记录每一步的输入、输出、LLM决策、工具执行结果方便事后复盘。这些日志后来还成了我优化提示词的重要参考。6. 自动化解题的能力边界与个人思考跑了几十道题目之后我对这套系统的能力边界有了比较清晰的认识。简单题和中等题尤其是Web方向的信息收集、密码学的常规编码解码、杂项的文件分析自动化成功率能达到70%以上。但逆向和PWN方向成功率明显下降大概只有30%左右。需要多步推理和创造性思维的题目基本还是得靠人类。这个结果其实符合预期。当前的大语言模型在模式匹配和常规推理上表现不错但在需要真正理解程序行为、进行跨领域知识迁移的场景下还是有明显短板。不过我觉得这套系统的价值不在于完全替代人类而在于把人类从重复劳动中解放出来。信息收集、编码转换、常规漏洞测试这些环节交给自动化去做人类选手可以把精力集中在更有创造性的部分。后续我打算继续优化的方向有几个一是加入更多工具尤其是动态分析工具提升逆向和PWN方向的自动化能力二是优化提示词让LLM在决策时能更好地利用历史信息三是尝试多模型协作用不同模型负责不同环节取长补短。最后分享一个我在调试过程中总结的小技巧不要追求一步到位先让系统能跑通最简单的题目然后逐步增加难度。我一开始就想让系统解决所有方向的题目结果每个方向都调不通。后来我先把Web方向的简单题跑通确保整个流程没有bug然后再逐步加入密码学、杂项、逆向。这种渐进式的开发方式比一上来就搞大而全要高效得多。