LibreSSL与OSS-Fuzz集成:发现和修复内存损坏漏洞

本文详细介绍了将LibreSSL集成到Google的OSS-Fuzz模糊测试平台的过程,发现了14个以上新漏洞,包括ASN.1解析器中的内存读取漏洞,并获得了Google的1万美元奖励。

LibreSSL和OSS-Fuzz

2020年4月8日 - 作者:Andrea Brancaleoni

一个模糊测试集成奖励的故事

在我在Doyensec的第一个月,我有机会将我的工作和业余爱好结合起来。我利用Doyensec提供的25%研究时间,将LibreSSL库集成到OSS-Fuzz中。

LibreSSL是OpenSSL的API兼容替代品,在Heartbleed攻击之后,它被认为是OpenBSD、macOS和VoidLinux上OpenSSL的成熟替代品。

在这项研究的背景下,我们获得了Google的10,000美元奖金,其中100%捐赠给了癌症研究所。模糊测试器还发现了14个以上的新漏洞,其中四个直接与内存损坏相关。在接下来的段落中,我们将介绍将新项目移植到OSS-Fuzz的过程,从遵循社区提供的步骤到实际的代码移植,我们还将展示在136e6c997f476cc65e614e514ac3bf6ee54fc4b4提交中修复的一个漏洞。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
commit 136e6c997f476cc65e614e514ac3bf6ee54fc4b4
Author: beck <>
Date:   Sat Mar 23 18:48:15 2019 +0000

    Add range checks to varios ASN1_INTEGER functions to ensure the

    13799 from oss-fuzz
    ok tb@ jsing@

 src/lib/libcrypto/asn1/a_int.c    | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/lib/libcrypto/asn1/tasn_prn.c |  8 ++++++--
 src/lib/libcrypto/bn/bn_lib.c     |  4 +++-
 3 files changed, 62 insertions(+), 6 deletions(-)

FOSS历史学家的模糊书籍

作为voidlinux的维护者,我是LibreSSL的长期用户和支持者。LibreSSL是2014年从OpenSSL分叉出来的TLS/加密堆栈版本,目标是现代化代码库、提高安全性并应用最佳实践开发流程。这种分叉的动机是在发现Heartbleed漏洞之后产生的。

LibreSSL的努力旨在移除目标平台认为无用的代码,移除代码异味,并以兼容性为代价包含额外的安全默认设置。LibreSSL代码库现在几乎是OpenSSL大小的70%(237558 cloc vs 335485 cloc),同时在所有主要现代操作系统上实现了类似的API。

分叉被认为是一件坏事,不仅因为它意味着未来会浪费大量精力,而且因为分叉往往伴随着后继团体之间在合法性、继承和设计方向问题上的大量冲突和尖刻。存在严重的社会压力反对分叉。因此,主要的分叉(如Gnu-Emacs/XEmacs分裂、386BSD团体分裂成三个子项目,以及短暂的GCC/EGCS分裂)非常罕见,以至于它们在黑客民间传说中被单独记住。——Eric Raymond《 homesteading the Noosphere》

LibreSSL的努力普遍受到好评,现在它取代了OpenBSD、macOS自10.11以来的OpenSSL,以及许多其他Linux发行版。在最初的几年里,OpenSSL中发现了6个关键漏洞,没有一个影响LibreSSL。

历史上,这类分叉往往会产生竞争项目,这些项目后来无法交换代码,将潜在的开发者池分开。然而,LibreSSL团队在很大程度上证明了能够合并和实施新的OpenSSL代码和错误修复,同时精简原始源代码并减少很少使用或危险的功能。

OSS-Fuzz选择

虽然LibreSSL的开发似乎是一个有幸福结局的故事,但将模糊测试和安全审计集成到项目中的情况却远非如此。Heartbleed漏洞就像行业的警钟,要求解决构成互联网核心的库的安全性。特别是,Google开放了OSS-Fuzz项目。

OSS-Fuzz是一项努力,免费提供Google基础设施,对最流行的开源库执行模糊测试。事实上,执行这些测试的第一个项目是OpenSSL。

模糊测试是一种众所周知的发现软件中编程错误的技术。许多这些可检测的错误,如缓冲区溢出,可能具有严重的安全隐患。OpenSSL在c38bb72797916f2a0ab9906aad29162ca8d53546中包含了模糊测试器,并于2016年晚些时候集成到OSS-Fuzz中。

1
2
3
4
5
6
7
commit c38bb72797916f2a0ab9906aad29162ca8d53546
Refs: OpenSSL_1_1_0-pre5-217-gc38bb72797
Author:     Ben Laurie <ben@links.org>
AuthorDate: Sat Mar 26 17:19:14 2016 +0000
Commit:     Ben Laurie <ben@links.org>
CommitDate: Sat May 7 18:13:54 2016 +0100
    Add fuzzing!

由于LibreSSL和OpenSSL共享大部分代码库,LibreSSL主要实现OpenSSL的安全子集,我们认为将OpenSSL模糊测试器移植到LibreSSL将是一个有趣且有用的项目。此外,这导致了几个内存相关损坏错误的发现。

需要注意的是,以下细节不会取代官方的OSS-Fuzz指南,而是有助于选择OSS-Fuzz集成的好目标项目。一般来说,申请新的OSS-Fuzz集成包括四个逻辑步骤:

  1. 选择:选择一个尚未移植的新项目。检查OSS-Fuzz项目目录中的现有项目。例如,检查是否有人已经在拉取请求中尝试执行相同的集成。
  2. 可行性:检查该项目在互联网上的可行性和安全影响。作为一般指南,项目对网络日常使用的影响越大,奖金就越大。在撰写本文时,OSS-Fuzz奖金通过Google补丁奖励计划高达20,000美元。另一方面,任何集成都需要开发良好的覆盖范围。因此,集成已经采用模糊测试器的项目更容易。
  3. 技术集成:遵循超级详细的入门指南执行初始集成。
  4. 利润:申请Google补丁奖励计划。利润?!

我们获得了奖金,我们帮助保护了互联网一点点。你也应该这样做!

心碎

在发现崩溃后,OSS-Fuzz基础设施提供了一个最小化的测试用例,可以由分析师检查。问题是在ASN.1解析器中发现的。ASN.1是一种形式符号,用于描述电信协议传输的数据,无论这些数据的语言实现和物理表示如何,无论是复杂的还是非常简单的。巧合的是,它用于x.509证书,这代表了构建公钥基础设施的技术基础。

通过dumpasn1传递我们的测试用例0202 ff25,可以看到它如何出错,说长度为2(字节)的整数用负值编码。这在ASN.1中是不允许的,在LibreSSL中也不应该允许。然而,正如OSS-Fuzz所发现的,这个测试使Libressl解析器崩溃。

1
2
3
4
5
6
7
8
$ xxd ./test
xxd ../test
00000000: 0202 ff25                                ...%
$ dumpasn1 ./test
  0   2: INTEGER 65317
       :   Error: Integer is encoded as a negative value.

0 warnings, 1 error.

由于LibreSSL的实现没有防范负整数,试图将精心制作的负ASN.1整数转换为BIGNUM的内部表示,并导致不受控制的过度读取。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==1==ERROR: AddressSanitizer: SEGV on unknown address 0x00009fff8000 (pc 0x00000058a308 bp 0x7ffd3e8b7bb0 sp 0x7ffd3e8b7b40 T0)
    ==1==The signal is caused by a READ memory access.
    SCARINESS: 20 (wild-addr-read)
        #0 0x58a307 in BN_bin2bn libressl/crypto/bn/bn_lib.c:601:19
        #1 0x6cd5ac in ASN1_INTEGER_to_BN libressl/crypto/asn1/a_int.c:456:13
        #2 0x6a39dd in i2s_ASN1_INTEGER libressl/crypto/x509v3/v3_utl.c:175:16
        #3 0x571827 in asn1_print_integer_ctx libressl/crypto/asn1/tasn_prn.c:457:6
        #4 0x571827 in asn1_primitive_print libressl/crypto/asn1/tasn_prn.c:556
        #5 0x571827 in asn1_item_print_ctx libressl/crypto/asn1/tasn_prn.c:239
        #6 0x57069a in ASN1_item_print libressl/crypto/asn1/tasn_prn.c:195:9
        #7 0x4f4db0 in FuzzerTestOneInput libressl.fuzzers/asn1.c:282:13
        #8 0x7fd3f5 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:529:15
        #9 0x7bd746 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/libfuzzer/FuzzerDriver.cpp:286:6
        #10 0x7c9273 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:715:9
        #11 0x7bcdbc in main /src/libfuzzer/FuzzerMain.cpp:19:10
        #12 0x7fa873b8282f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/libc-start.c:291
        #13 0x41db18 in _start

这种"野生"地址读取可能被恶意行为者用于在安全敏感上下文中执行泄漏。Libressl维护团队不仅及时解决了漏洞,还在46e7ab1b335b012d6a1ce84e4d3a9eaa3a3355d9中包含了进一步保护,以防止缺少ASN1_PRIMITIVE_FUNCS。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
commit 46e7ab1b335b012d6a1ce84e4d3a9eaa3a3355d9
Author: jsing <>
Date:   Mon Apr 1 15:48:04 2019 +0000

    Require all ASN1_PRIMITIVE_FUNCS functions to be provided.

    If an ASN.1 item provides its own ASN1_PRIMITIVE_FUNCS functions, require
    all functions to be provided (currently excluding prim_clear). This avoids
    situations such as having a custom allocator that returns a specific struct
    but then is then printed using the default primative print functions, which
    interpret the memory as a different struct.

对陌生人关闭大门

模糊测试,尽管被视为发现安全漏洞的最简单方法之一,但仍然非常有效。即使OSS-Fuzz特别针对开源项目,它也可以适应闭源项目。事实上,以实现LLVMFuzzerOneInput接口为代价,它集成了所有最新和最伟大的clang/llvm模糊测试器技术。

随着Dockerfile语言在开发运维方面的巨大改进,我们强烈认为OSS-Fuzz模糊测试接口定义语言也应该用于每个非平凡的闭源项目。如果你需要帮助,请联系我们进行安全自动化项目!

一如既往,这项研究得益于Doyensec提供的25%研究时间。请继续关注新剧集!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计