✨ 要点🔬 技术摘要
想象你是一名安全检查员,正试图在一座庞大而复杂的工厂中发现隐藏的陷阱。这座工厂是用Go 编程语言 编写的一段软件。
长期以来,安全检查员拥有一种名为Zorya 的特殊工具,它非常擅长检查小型、简单的工厂(称为"TinyGo"二进制文件)。但像 Kubernetes 和 Ethereum 这样的大公司所使用的现实世界工厂,规模巨大、混乱不堪,并且同时由许多工人(线程)运行。旧的 Zorya 工具无法应对这些大型工厂;它会被噪音和复杂性搞得晕头转向。
本文讲述的是如何升级 Zorya,使其最终能够检查这些现实世界中多工种的 Go 工厂。以下是他们如何实现这一点的简明解释:
1. 问题:“繁忙的工厂”
标准的 Go 编译器(称为gc )构建的软件会启动一整支无形的工人队伍(操作系统线程)来管理工作。它还有一个“交通指挥员”(运行时),可以在任何时候停止任何一名工人,让其他人优先通行。
旧工具 :Zorya 原本用于检查安静、单工人的工厂。当它试图检查繁忙的多工人工厂时,它无法弄清楚谁在做什么,或者工人们站在哪里。
目标 :让 Zorya 变得足够聪明,能够暂停混乱,拍摄每位工人的快照,然后仔细检查工作而不致迷失。
2. 解决方案:三种新超能力
作者赋予了 Zorya 三种新技巧来处理大型工厂:
“时间旅行快照”(恢复线程状态) : 想象工厂全速运转。与其试图实时观察工人的移动(这太快且令人困惑),新的 Zorya 会按下“暂停”键,拍摄每位工人的手、工具和位置的高清照片并保存。当它开始检查时,会重新加载这些照片,从而确切知道每个人在开始前的位置。这使它能够忽略“交通指挥员”带来的混乱,专注于实际代码。
“假设”镜像(覆盖路径分析) : 通常,当一名工人到达分岔路口时,他们会选择一条路径并沿其行走,而另一条路径则被忽略。
旧方法 :Zorya 只会检查工人实际走过的路径。
新方法 :Zorya 创建了一个工厂的“幽灵镜像”。当工人选择左路时,Zorya 会派遣一名“幽灵工人”沿右路走几步。它会检查该路径是否存在陷阱(例如地板上的洞或损坏的工具),而无需实际行走。如果幽灵发现了陷阱,Zorya 就会发出警报。这被称为写时复制(Copy-on-Write) :它只复制幽灵接触到的工厂部分,从而节省大量能量。
“静默陷阱”检测器 : 有些陷阱不会发出响亮的声音(如崩溃或恐慌)。例如,一个数字可能变得太大而“回绕”并再次变小,静默地破坏数学运算。其他工具会错过这些,因为它们只寻找响亮的崩溃。Zorya 使用一个超级聪明的数学大脑(称为SMT 求解器 )在脑海中进行计算。即使程序没有崩溃,它也能说:“嘿,如果这个数字变大,它将静默地破坏数学运算。”
3. 测试:发现真实漏洞
该团队在 Kubernetes、Go-Ethereum 和 CoreDNS 等著名软件中发现的11 个真实世界安全漏洞 上测试了升级后的 Zorya。他们将 Zorya 与其他工具进行了比较,包括静态检查器(像语法检查器一样读取代码)、模糊测试工具(向软件投掷随机数据)以及其他安全扫描器。
结果 :
Zorya 发现了 11 个漏洞中的 7 个。
“静默”胜利 :Zorya 发现的一个漏洞是“静默整数溢出”。这是一个数学错误,既没有导致程序崩溃,也没有触发警报。没有其他工具发现此漏洞 ,除非有人手动告知它们具体要寻找什么。Zorya 自动发现了它。
权衡 :Zorya 比“投掷随机数据”的工具(模糊测试工具)慢。虽然模糊测试工具可能在几秒钟内发现崩溃,但 Zorya 发现一个漏洞大约需要 16 分钟。然而,Zorya 不需要人类为每个函数编写特定的测试脚本;它直接分析二进制文件。
4. 结论
本文表明,我们现在可以利用先进的“幽灵工人”检查方法,在复杂的多线程 Go 软件中发现深层、隐藏的安全漏洞。虽然它比其他方法耗时稍长,但它能够发现其他工具完全遗漏的“静默”漏洞,从而使我们的数字基础设施更安全。
简而言之 :他们教会了一个安全机器人如何暂停一个混乱的工厂,拍摄工人的快照,并检查无人行走的路径,成功发现了以前不可见的隐藏陷阱。
技术摘要:从 TinyGo 到 gc 编译器:扩展 Zorya 的混合执行框架以分析现实世界的 Go 二进制文件
问题陈述
对使用标准 gc 编译器编译的 Go 二进制文件进行安全分析仍然是一个重大挑战。与使用 TinyGo 编译的二进制文件(生成具有最小运行时的单线程可执行文件)不同,gc 编译的二进制文件利用复杂的运行时来管理 goroutine、垃圾回收以及跨多个操作系统线程的抢占式调度。现有的符号执行工具(例如 KLEE、angr、Radius2)主要针对 C/C++ 设计,并依赖 LLVM 中间表示(IR),而 Go 并未完全编译到该表示。此外,这些工具通常无法建模 Go 特定的运行时机制,如协作式/异步抢占、goroutine 调度以及内存映射的 VDSO 函数,导致它们在面对生产环境的 Go 二进制文件时失效。Zorya 框架的先前版本仅限于 TinyGo 二进制文件,留下了对现实世界多线程 Go 应用程序进行分析的空白。
方法论
本文提出了对 Zorya 的扩展,Zorya 是一个将编译后的二进制文件提升到 Ghidra 的 P-Code 中间表示的混合执行框架。该扩展通过以下三个主要技术机制实现了对多线程 gc 编译二进制文件的分析:
多线程状态恢复与调度:
Zorya 在初始化时从 gdb 转储中恢复所有操作系统线程的状态,捕获寄存器状态、线程局部存储(TLS)基址和回溯信息。
线程被分类(例如主线程、系统监控器、等待中),以促进调度。
该框架中和了运行时抢占,并在函数模式分析中采用“仅主线程”调度策略,将混合执行限制在主线程,以避免垃圾回收或系统监控器的中断。这使得能够连续探索用户级函数。
具有写时复制(CoW)语义的覆盖路径分析:
为了解决路径爆炸问题并推理未执行的分支,而无需复制整个状态(对于 gc 二进制文件,这可能会超过 1 GiB),Zorya 实现了一种覆盖机制。
当条件分支涉及跟踪的符号变量时,会为未执行的分支创建一个轻量级覆盖层。读取操作首先查询覆盖层,若未命中则回退到基础状态;写入操作则专门写入覆盖层。
该覆盖层执行有限数量的指令(默认 N = 15 N=15 N = 15 )后被丢弃,从而允许在未被具体轨迹执行的分支上检测漏洞。
通过分析器例程进行漏洞检测:
该框架使用具体值(来自 gdb 转储)和符号表达式(由 Z3 SMT 求解器管理)来执行指令。
一个“分析器例程”在每个指令处检查漏洞模式,包括空指针解引用、整数溢出和除以零。
对于 gc 二进制文件,系统利用 AST 探索(以定位显式的 panic 调用)和覆盖执行(以检测不会触发运行时 panic 的静默漏洞)。
主要贡献
扩展至 gc 二进制文件: 该框架被扩展以分析由标准 Go 编译器生成的多线程二进制文件,弥合了研究工具与生产环境 Go 软件之间的差距。
现实世界漏洞数据集: 作者整理了一个包含 11 个现实世界漏洞的语料库,这些漏洞来自生产项目(包括 Kubernetes、Go-Ethereum 和 CoreDNS),并附带完整的复现工作流和触发输入。
比较评估: Zorya 与七种最先进的工具进行了评估(三个静态分析器、两个模糊测试器和两个二进制级符号执行器)。
静默漏洞检测: 该框架成功检测了不会触发运行时 panic 的漏洞,特别是静默整数溢出,而无需手动编写的预言机。
结果
评估在 11 个现实世界漏洞上进行,涵盖三类:空指针解引用、整数溢出和索引越界。
检测率: Zorya 检测到了 11 个漏洞中的 7 个 。
4 个 由分析器例程在具体(已执行)路径上捕获。
3 个 通过未执行分支上的 AST panic 可达性识别。
2 个 侧面发现是通过在未执行路径上的覆盖执行(在 15 条指令的深度限制内)揭示的。
独特检测: Zorya 是唯一检测到 Go-Ethereum (v1.6.0) 中 memoryGasCost 函数内静默整数溢出的工具。该漏洞涉及 Go 无符号算术中的乘法静默回绕,允许攻击者以接近零的 Gas 成本分配海量内存。没有其他被评估的工具在没有手动编写预言机的情况下发现此漏洞。
工具比较:
静态分析器 (staticcheck, gosec, nilaway): 检测到了 11 个漏洞中的 0 个。gosec 漏掉了同类型算术溢出,而 nilaway 由于依赖解析问题在 Kubernetes 包上失效。
模糊测试器 (go test -fuzz, GoLibAFL): 检测到了 11 个漏洞中的 5 个(包括 kube-sm-2025,Zorya 因 runtime.memmove 符号执行中的资源耗尽而漏掉)。模糊测试器速度更快(平均约 0.18 秒至 7 秒),但需要手动编写的 harness,并且漏掉了不会导致崩溃的静默漏洞。
其他符号执行器 (BINSEC, SymQEMU): 检测到了 11 个漏洞中的 0 个,主要是由于缺乏对 Go 运行时原语的支持。
性能: Zorya 平均每个检测耗时 16.5 分钟,显著慢于模糊测试器,但它提供完整的指令级执行轨迹,并且完全自动运行,无需 harness。
意义与主张
本文声称 Zorya 解决了 Go 安全领域的一个关键空白。虽然静态分析器无法推理特定于程序的算术和别名问题,而模糊测试器需要手动 harness 且漏掉非崩溃漏洞,但 Zorya 提供了一种完全自动的二进制级分析能力,能够检测静默漏洞。
作者将 Zorya 定位为一种专门针对 Go 二进制文件的工具,结合了细粒度的覆盖探索、多线程初始状态恢复和静默溢出检测。这项工作证明了混合执行可以适应标准 Go 编译器复杂的多线程运行时,从而能够检测到其他被评估工具看不见的漏洞(如静默整数溢出)。本文结论认为,尽管 Zorya 比模糊测试慢,但其提供精确指令级轨迹和检测非崩溃漏洞的能力,使其成为软件安全工程工具包中有价值的补充。
每周获取最佳 computer science 论文。
受到斯坦福、剑桥和法国科学院研究人员的信赖。
请查收邮箱确认订阅。
出了点问题,再试一次?
无垃圾邮件,随时退订。