(论文阅读)Go or No Go-Differential Fuzzing of Native and C Libraries

Go or No Go: Differential Fuzzing of Native and C Libraries

时间:2023.5

作者:Alessandro Sorniotti(IBM)、Michael Weissbacher、Anil Kurmus

会议:S&P‘2023

Abstract

​ 十多年来,Go 已经成为当今最流行的编程语言之一。Go 是一种静态类型的编译语言,通过强类型、自动插入的边界检查和标记-清扫垃圾收集器,实现了空间和时间上的内存安全性。Go 开发人员可以即时使用大量的本地库,这些库可以作为运行时的一部分提供,也可以从社区代码中导入;或者,Go 开发人员可以直接链接到 C/C++ 库,这些库可以通过cgo功能从GO源码中调用。做出支持以上功能的这一决定的原因包括稳定性、性能和可用性。因此,开发人员可以在 Go 本地库或非本地代码之间做出选择。然而,如今人们对如何在这一决策中考虑安全问题还知之甚少。

我们的研究首次探讨了 Go 程序在本地库和非本地库之间做出选择的安全影响。我们首先调查了流行的 GitHub 项目在多大程度上使用了 cgo,结果发现这种选择实际上相当流行。然后,我们设计并构建了一个differential fuzzer,它可以比较相同功能的本地和 C/C++ 实现。我们实现了该fuzzer,并在四个流行软件包(libcrypto、libpng、libssl 和 libz)上测试了其有效性,描述了结果并强调了它们的安全影响。最后,我们介绍了两个真实世界的案例研究(anti-virus evasion,包括 Gmail 中包含的反病毒扫描仪和证书透明度案例研究),并讨论了我们的differential fuzzer是如何发现具有安全影响的实现差异的。我们的工作促使 Golang zlib 发生了变化,这些变化已经发布。

Background

​ Go 是一种编程语言,因其安全优势和并发性而广受赞誉。该语言默认情况下是内存安全的,并克服了 C/C++ 等语言数十年来的安全问题。然而,在使用库来利用常用功能时,开发人员面临着一个艰难的选择: 使用本地 Go 库或非本地 C/C++(使用编译器/运行时的 cgo 功能)。目前,影响这一决定的因素包括可用性、性能和稳定性。

​ 尽管 Go 提供了大量库,但并非所有库都能在 Go 中使用,开发人员可能需要按照规范重新实现功能。这不仅成本高昂,而且容易出错。在决定使用本地库还是非本地库时,性能也是一个考虑因素,因为使用 C/C++ 库可以为大量使用此类功能的程序带来性能优势。稳定性是另一个因素,因为库的成熟度各不相同。Go 库是从零开始实现的,但可能缺少大量的测试,而 C/C++ 库可能有陈旧的代码,但经过了数十年的测试。

​ 除了可用性、性能、稳定性等因素外,在做出这一决定时还应考虑安全问题,因为无论哪种方案都会涉及安全问题。如果开发人员重用现有的 C 代码,就有可能引入 C 库中可能存在的内存安全问题。如果重新实现 Go,则可能在规范或实现层面引入 C 库版本中不存在的新缺陷。更广义地说,不同设计和实现的库可能会在输出结果上产生偏差。从语言理论的角度来看,我们可以将其视为解析树差异攻击的一个实例[38]、[30]、[37]:相同协议/语言存在两种不同的解析器,它们之间的差异可能会导致安全问题。遗憾的是,对于无上下文语言来说,正式验证两个解析器是否等价是无法判定的[29],这就促使人们采用灰盒模糊(greybox fuzzing)等实用但不完整的方法。

Contribution

​ 在本文中,我们提出并实现了一种方法,用于研究在 Go 编程语言中使用本地库与非本地库所产生的问题。特别是,我们通过使用差分模糊(differential fuzzing)来寻找这两类库之间的差异,重点关注差异可能导致广泛安全影响的常用库。

​ 我们采用了一种有效的差异模糊方法,利用现有的fuzzer,针对两个库版本中的任何一个生成输入语料库和harness。对于每个输入,我们都会比较两个库的输出(可能还有其他副作用)。例如,就解析库而言,如果相同的输入导致两种不同的解析输出,则可能存在潜在缺陷。仅根据解析结果,并不能立即看出两个解析器中哪个偏离了规范(如果有的话)。具体来说,安全漏洞可能仅仅来自于差异,而不是一个解析器误解了输入。

​ 我们还介绍了两个案例研究:在第一个案例研究中,我们展示了如何破坏 libz 压缩数据的标头,从而导致 19 种反病毒(AV)产品和 Gmail 中包含的 AV 扫描仪出现漏洞。在附录提供的第二部分中,我们展示了解析器错配如何影响证书透明度基础设施。对于所有受影响的产品,我们都启动了负责任的披露程序。

​ 我们的研究结果表明(i) 从安全角度来看,Go 开发人员在 Go 实现库和 C/C++ 库之间的选择并不简单;(ii) 差异模糊是发现库实现之间解析器差异的有效方法,应在 C 库的 Go 再实现中系统地使用;(iii) 解析器差异可能导致重要的安全问题。

我们的主要贡献有:

  1. 我们设计了一种定制的differential fuzzer,以发现 Go 程序所用库中与安全相关的解析差异;
  2. 我们实现了设计原型,支持广泛使用的 libcrypto、libpng、libssl 和 libz 库;
  3. 我们对fuzzer的独特差异进行了广泛评估,并分析了根本原因和其潜在影响;
  4. 我们介绍了两个case-study,其中发现的解析器差异导致了安全问题。一项研究影响了证书透明度,一项研究绕过了在 Virus Total 和 Gmail 上测试的 19 个防病毒系统。

Some Questions

1. How to choose/generate Fuzz target for C/C++ library?

​ 作者选用的待测试库(asn1,libpng,libcrypto,libzip)在go中都有现成的fuzz harness,然后将其转化为等价的C/C++ api,生成C的fuzz harness.

2. How to locate the root cause of discrepancy?

​ 没说,大概率是手动分析。