Unboxing BusyBox - Claroty和JFrog发现的14个新漏洞

BusyBox拆箱

背景

具有有限内存和存储资源的嵌入式设备可能会利用诸如2022世界杯阿根廷预选赛赛程BusyBox它被誉为嵌入式Linux中的瑞士军刀。BusyBox是一个由许多有用的Unix实用程序(称为applet)组成的软件套件,它们被打包为单个可执行文件。在BusyBox中,您可以找到功能完备的shell、DHCP客户端/服务器和小型实用程序,例如cplsgrep等。您可能会发现许多OT和IoT设备正在运行BusyBox,包括流行的可编程逻辑控制器(plc)、人机界面(hmi)和远程终端单元(rtu)——其中许多现在运行在Linux上。

作为我们承诺的一部分提高开源软件的安全性,Claroty的Team82和JFrog合作了一个漏洞研究项目,检查BusyBox。通过使用静态和动态技术,Claroty的Team82和JFrog发现了影响BusyBox最新版本的14个漏洞。所有漏洞都是由BusyBox在1.34.0版本私下披露并修复的8月19日上映

在大多数情况下,这些问题的预期影响是拒绝服务(DoS)。然而,在更罕见的情况下,这些问题也可能导致信息泄露和远程代码执行。

在本报告中,我们提供了我们发现的漏洞的详细信息,详细说明了谁受到影响,讨论了我们的研究方法,深入解释了其中一个漏洞,并提出了针对这些问题的修复和解决方案。

除了披露漏洞外,Team82还开源我们定制的AFL模糊吊带,这是触发许多提到的漏洞。希望这将帮助其他研究人员发现和揭示更多的问题。

的漏洞

CVE ID 描述 影响applet 受影响版本(含) 影响 CVSS v3.1
cve - 2021 - 42373 中的空指针解引用男人。当提供了节名但没有给出页参数时,将导致拒绝服务 男人。 1.33.0-1.33.1 DoS 5.1
cve - 2021 - 42374 读取超出边界的堆unlzma当精心制作的lzma压缩输入被解压缩时,会导致信息泄漏和拒绝服务。这可以由任何内部支持LZMA压缩的applet/format触发。 lzma/unlzma以及更多信息(见下文) 1.27.0 - 1.33.1 DoS和InfoLeak 6.5
cve - 2021 - 42375 中特殊元素的错误处理在处理精心制作的shell命令时,由于shell将特定字符误认为保留字符,导致拒绝服务。这可能用于在过滤命令输入的极少数情况下的DoS。 1.33.1 DoS 4.1
cve - 2021 - 42376 中的空指针解引用在处理精心制作的shell命令时导致拒绝服务,因为在\ x03分隔符字符。这可能用于非常罕见的过滤命令输入条件下的DoS。 1.16 1.31.1 DoS 4.1
cve - 2021 - 42377 攻击者控制的指针由于shell错误地处理了&&&字符串,导致在处理精心制作的shell命令时拒绝服务并可能执行代码。在过滤命令输入的极少数情况下,这可以用于远程代码执行。 1.33.0-1.33.1 DoS和可能的RCE 6.4
cve - 2021 - 42378 免费使用awk导致拒绝服务,并可能在处理一个精心制作的代码执行awk模式中的getvar_i函数 awk 1.16 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42379 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行next_input_file函数 awk 1.18 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42380 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行clrvar函数 awk 1.28 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42381 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行hash_init函数 awk 1.21 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42382 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行getvar_s函数 awk 1.26 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42383 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行评估函数 awk 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42384 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行handle_special函数 awk 1.18 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42385 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行评估函数 awk 1.16 1.33.1 DoS和可能的RCE 6.6
cve - 2021 - 42386 免费使用awk中处理精心制作的awk模式时,可能会导致拒绝服务和代码执行nvalloc函数 awk 1.16 1.33.1 DoS和可能的RCE 6.6

触发漏洞

由于受影响的applet不是守护进程,因此只有在向易受攻击的applet提供不受信任的数据(通常通过命令行参数)时,才能利用每个漏洞。具体来说,这些是触发每个漏洞必须发生的条件:

cve - 2021 - 42373-如果攻击者可以控制传递给的所有参数,则适用男人。

男人。是由默认的BusyBox配置构建的,但没有附带Ubuntu默认的BusyBox二进制文件。

cve - 2021 - 42374-适用于攻击者可以提供一个精心制作的压缩文件,该文件将通过使用unlzma

注意,即使unlzma applet不可用,但是CONFIG_FEATURE_SEAMLESS_LZMA(默认启用)是启用的,其他小程序如焦油解压缩rpmdpkg, lzma而且男人。还可以在处理文件时使用.lzma文件名后缀。

unlzma由默认的BusyBox配置构建,并附带Ubuntu默认的BusyBox二进制文件。

cve - 2021 - 42375-如果攻击者能够提供命令行,则适用包含特殊字符$,{,},#。

由默认的BusyBox配置构建,并附带Ubuntu默认的BusyBox二进制文件。

cve - 2021 - 42376-如果攻击者能够提供命令行,则适用它包含特殊字符\x03(分隔符)。

是由默认的BusyBox配置构建的,但没有附带Ubuntu默认的BusyBox二进制文件。

cve - 2021 - 42377-如果攻击者能够提供命令行,则适用,包含特殊字符&。

Cve-2021-42378 - cve-2021-42386-如果攻击者可以提供任意模式,则适用awk(模式是这个applet接受的第一个位置参数)。

awkƒ由默认的BusyBox配置构建,并附带Ubuntu默认的BusyBox二进制文件。

研究方法

为了研究BusyBox,我们使用了静态和动态分析方法。

首先,以自顶向下的方法(从用户输入到特定的applet处理)对BusyBox源代码进行手动检查。我们还寻找了明显的逻辑/内存损坏漏洞。

接下来的方法是模糊。我们编译了BusyBox峨山并实现了AFL每个BusyBox小程序。每个线束随后通过删除不必要的代码部分进行优化,在同一进程上运行多个模糊周期(持续的模式),并并行运行多个模糊实例。

我们从模糊所有守护进程小程序开始,包括HTTP、Telnet、DNS、DHCP、NTP等。为了有效地模糊基于网络的输入,需要进行许多代码更改。例如,我们执行的主要修改是将所有recv函数替换为来自STDIN的输入,以支持模糊输入。当我们模糊非服务器小程序时也做了类似的更改。

我们为每个applet准备了几个示例,并在几天内运行了数百个模糊的BusyBox实例。这给了我们成千上万的事故评估。我们必须创建具有相同根本原因的崩溃类别,以帮助减少样本集中的崩溃数量。后来,我们最小化每个组代表,以便处理唯一崩溃输入的一个小子集。

为了完成这些任务,我们开发了自动工具来消化所有的崩溃数据,并根据崩溃分析报告进行分类,该报告主要包括崩溃堆栈跟踪、寄存器和相关代码区的汇编代码。例如,我们合并了具有相似崩溃堆栈跟踪的案例,因为它们通常具有相同的问题根源。

最后,我们研究了每个独特的崩溃,并最小化其输入向量,以了解根本原因,这使我们能够创建一个利用导致崩溃的漏洞的概念证明(PoC)。此外,我们还针对几个BusyBox版本测试了poc,以了解何时将错误引入源代码。

总之,以下是我们在研究中采取的步骤:

  1. 代码评审
  2. 起毛
  3. 减少和最小化
  4. 伤检分类
  5. PoC
  6. 测试多个版本
  7. 信息披露

BusyBox Fu2022世界杯阿根廷预选赛赛程zzing指南和资源

作为我们对开源安全和安全社区承诺的一部分,我们创建了一个简单的入门指南,详细介绍了如何模糊BusyBox。该指南与我们所写的作为我们的fuzzing努力的一部分的fuzzing脊一起出版。我们希望社区能够进一步改进这些fuzzing工具,以便在BusyBox中发现和修复更多的bug。

所有资料均可在Claroty的GitHub页面

威胁分析

为了评估这些漏洞构成的威胁级别,我们检查了JFrog的数据库中超过10,000个嵌入式固件图像(仅由公开可用的固件图像组成,而不是上传到JFrog Artifactory的图像)。我们发现其中40%包含一个BusyBox可执行文件,该文件与受影响的小程序之一链接,使得这些问题在基于linux的嵌入式固件中非常普遍。

然而,我们认为这些问题目前并不构成严重的安全威胁,因为:

  1. DoS漏洞很难利用,但applet几乎总是作为一个独立的fork进程运行,这一事实通常会减轻其影响。
  2. 利用信息泄漏漏洞并非易事(请参阅下一节)。
  3. 免费后使用漏洞可能被用于远程代码执行,但目前我们没有试图为它们创建武器化漏洞。此外,很少(并且本质上不安全)处理awk来自外部输入的模式。

深潜CVE-2021-42374 - LZMA OOB读取

Lempel-Ziv-Markov链算法(LZMA)与距离编码

LZMA是一种使用字典压缩并使用范围编码器对其输出进行编码的压缩算法。字典压缩器使用复杂的字典数据结构找到匹配,并产生文字符号和短语引用流,由范围编码器一次编码一位,使用复杂的模型对每个位进行概率预测。

压缩算法使用自适应二进制范围编码器将压缩流编码为比特流。数据被分解成包,每个包描述一个字节或一个LZ77序列,其长度和距离隐式或显式编码。

. LZMA格式由13字节的报头和LZMA压缩数据组成。下面是一个压缩字符串“abc”的小例子:LZMA文件格式

为了输出解压缩的流,LZMA实现使用了一个内存缓冲区,它被初始化为用户提供的字典大小(LZMA报头的一部分)。一旦缓冲区被填满,它自动输出迄今为止的数据,刷新缓冲区并开始再次填充。

该漏洞

的大小检查不足导致此漏洞unpack_lzma_stream函数(在decompress_unlzma.c中),当状态>=LZMA_NUM_LIT_STATES

While (global_pos + buffer_pos < header.dst_size){…uint32_t pos;Pos = buffer_pos - rep0;if ((int32_t)pos < 0) //检查不足pos += header.dict_size;// dict_size是用户控制的match_byte = buffer[pos];//读取OOB可能发生在这里do {int bit;Match_byte <<= 1;位= match_byte & 0x100;...

要触发漏洞并控制泄漏数据的起始偏移量,我们需要确保满足以下条件:

Buffer_pos = 0
而且
Rep0 = offset + dict_size

这种方式,pos将等于-(offset + dict_size).后添加dict_sizepos抵消因此,我们可以通过match_byte从期望的偏移量泄漏内存。泄漏的内存很可能包含指针,可以进一步帮助攻击者进行利用活动(例如通过促进ASLR绕过)。

导致越界访问

利用此漏洞的一般想法是准备一个专门制作的LZMA编码流,以便在解码时,两个条件都将被填充和pos会等于一个负数抵消.最终,解压缩的流将包含泄漏的内存,这些内存将被写入输出蒸汽。

满足第一个条件Buffer_pos = 0,我们需要确保我们的代码流(state >= LZMA_NUM_LIT_STATES)在当前解压缩的缓冲区流被刷新后到达,因此缓冲区指针的位置将为0。我们可以通过到达当前匹配的最后一个迭代来实现这一点:

Buffer [buffer_pos++] = previous_byte;If (buffer_pos == header.dict_size) {buffer_pos = 0;Global_pos += header.dict_size;If (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size) goto bad;IF_DESKTOP(total_written += header.dict_size;)} len——;} while (len != 0 && buffer_pos < header.dst_size);// match_last_iteration将以buffer_pos = 0结束;

第二个条件更难满足,需要对LZMA算法如何工作有深入的了解。一般的思想是在LZMA位流中编码一个特殊的长度,以便在解码时被rep0变量。

最后,为了达到OOB条件,我们需要写入一些字节,然后使用匹配来填充缓冲区头。dict_size和改变rep0我们想要的价值。因此,pos会相等抵消我们可以从offset中泄漏字节作为缓冲区指针的引用。

从越界内存泄漏位

阅读完match_byte,我们将得到这个流程:

Do {int bit;Match_byte <<= 1;位= match_byte & 0x100;Bit ^= (rc_get_bit(rc, prob + 0x100 + Bit + mi, &mi) << 8);/* 0x100或0 */ if(位)中断;} while (mi < 0x100);While (mi < 0x100) {rc_get_bit(rc, prob + mi, &mi);}

只要比特匹配我们的match_byte(泄漏的字节),它就会在读取概率的循环中Prob + 0x100 + bit + mi,但一旦有一位不匹配,它就从其中读取probb + mi.我们可以通过检查if来检测第一个不匹配的位是什么probb + mi通过写更多的字面值字节来改变,或者如果概率改变了,我们得到了不同的输出。最后,泄漏的比特将被刷新到解压缩的缓冲区。

ZIP文件武器化

虽然在LZMA解压缩算法中发现了该漏洞,但我们发现许多applet支持LZMA压缩,并将在默认情况下尝试解压缩已编码的LZMA流(有关管理此行为的配置标志,请参阅“修复和解决方案”部分)。例如,无处不在的ZIP格式支持LZMA压缩作为“类型14”压缩。

从攻击者的角度来看,ZIP是一个更好的攻击向量,因为:

  • 解压缩的调用比的直接调用常见得多unlzma
  • 使用这个攻击向量,对将要解压缩的文件名没有约束(不像tar攻击向量,它需要一个.lzma后缀)。
  • 泄露的数据可以被提取并保存到文件中,以后可以远程读取。例如,这可能发生在允许上传带有媒体资源的zip文件的嵌入式web服务中,这些文件将被提取到可访问的位置。2022世界杯阿根廷预选赛赛程从那里,攻击者可以读取泄漏的内存数据。

为了测试这一点,我们构建了一个小型PoC脚本,生成一个武器化ZIP,其中一个文件是使用LZMA压缩的:

测试PoC脚本

修复和变通方法

BusyBox 1.34.0 (直接下载链接),并鼓励用户升级。

如果不可能升级BusyBox(由于特定的版本兼容性需求),可以编译BusyBox 1.33.1和更早的版本,不使用易受攻击的功能(小程序)作为解决方案。

在运行使defconfig在BusyBox的源目录(或者如果重用以前的配置)中编辑config文件如下:

  • 男人。-删除注释CONFIG_MAN = y
  • lzma-删除注释CONFIG_UNLZMA = yCONFIG_FEATURE_SEAMLESS_LZMA = y而且CONFIG_FEATURE_UNZIP_LZMA = y
  • -删除注释CONFIG_ASH = y
  • -删除注释CONFIG_HUSH = y
  • awk-删除注释CONFIG_AWK = y

确认

我们要感谢BusyBox开发团队的Denys Vlasenko以迅速的方式验证并修复了所有上述问题对于版本1.34.0