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

背景
内存和存储资源有限的嵌入式设备可能会利用诸如2022世界杯阿根廷预选赛赛程BusyBox它在市场上被称为嵌入式Linux的瑞士军刀。BusyBox是一个软件套件,包含许多有用的Unix实用程序,称为applet,它们被打包为单个可执行文件。在BusyBox中,您可以找到一个完整的shell、一个DHCP客户端/服务器和一些小实用程序,例如cp,ls,grep等等。您可能会发现许多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/格式触发。 |
lzma/unlzma还有更多(见下文) |
1.27.0 - 1.33.1 | DoS和infolak | 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 | 应该做的和可能的RCE | 6.4 |
| cve - 2021 - 42378 | 使用后免费的awk导致拒绝服务,并可能在处理精心制作的代码时执行awk的模式getvar_i函数 |
awk |
1.16 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42379 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行next_input_file函数 |
awk |
1.18 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42380 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行clrvar函数 |
awk |
1.28 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42381 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行hash_init函数 |
awk |
1.21 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42382 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行getvar_s函数 |
awk |
1.26 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42383 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行评估函数 |
awk |
1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42384 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行handle_special函数 |
awk |
1.18 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42385 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行评估函数 |
awk |
1.16 1.33.1 | 应该做的和可能的RCE | 6.6 |
| cve - 2021 - 42386 | 使用后免费的awk类中处理精心制作的awk模式时,会导致拒绝服务和可能的代码执行nvalloc函数 |
awk |
1.16 1.33.1 | 应该做的和可能的RCE | 6.6 |
触发漏洞
由于受影响的applet不是守护进程,因此只有在向易受攻击的applet提供不受信任的数据(通常通过命令行参数)时,才能利用每个漏洞。具体来说,这些是触发每个漏洞必须发生的条件:
cve - 2021 - 42373—攻击者可以控制所有传递给攻击者的参数男人。。
男人。是由默认的BusyBox配置构建的,但没有随Ubuntu默认的BusyBox二进制文件一起发布。
cve - 2021 - 42374-适用于攻击者可以提供精心制作的压缩文件,该文件将通过使用解压unlzma。
注意,即使unlzma applet不可用,但是CONFIG_FEATURE_SEAMLESS_LZMA(默认启用),其他applet如焦油,解压缩,rpm,dpkg, 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(pattern是这个applet接受的第一个位置参数)。
awkƒ是由默认的BusyBox配置构建的,并与Ubuntu的默认BusyBox二进制文件一起发布。
研究方法
为了研究BusyBox,我们使用了静态和动态分析方法。
首先,采用自顶向下的方法对BusyBox源代码进行手动审查(跟踪用户输入直到特定的applet处理)。我们还寻找明显的逻辑/内存损坏漏洞。
下一种方法是模糊测试。编译BusyBox峨山并实现了AFL为每个BusyBox小程序使用。每个线束随后通过删除不必要的代码部分进行优化,在同一进程上运行多个模糊测试周期(持续的模式),并并行运行多个模糊实例。
我们从模糊测试所有守护程序applet开始,包括HTTP、Telnet、DNS、DHCP、NTP等。为了有效地模糊基于网络的输入,需要修改许多代码。例如,我们执行的主要修改是将所有的recv函数替换为来自STDIN的输入,以支持模糊输入。当我们对非服务器applet进行模糊处理时,也进行了类似的更改。
我们为每个applet准备了几个示例,并在几天内运行了数百个模糊的BusyBox实例。这让我们可以评估成千上万的崩溃。我们必须创建具有相同根本原因的崩溃类,以帮助减少样本集中的崩溃数量。后来,我们最小化了每个组代表,以便处理唯一崩溃输入的一小部分。
为了完成这些任务,我们开发了自动工具来消化所有的崩溃数据,并根据崩溃分析报告对其进行分类。崩溃分析报告主要包括崩溃堆栈跟踪、寄存器和相关代码区的汇编代码。例如,我们合并了具有类似崩溃堆栈跟踪的案例,因为它们通常具有相同的问题根源。
最后,我们研究了每个独特的崩溃并最小化其输入向量,以便了解根本原因,这使我们能够创建一个利用导致崩溃的漏洞的概念验证(PoC)。此外,我们针对几个BusyBox版本测试了poc,以了解bug是何时引入源代码的。
综上所述,我们在研究中采取了以下步骤:
- 代码评审
- 起毛
- 减少和最小化
- 伤检分类
- PoC
- 测试多个版本
- 信息披露
BusyBox模糊测2022世界杯阿根廷预选赛赛程试指南和资源
作为我们对开源安全和安全社区承诺的一部分,我们创建了一个简单的入门指南,详细介绍了如何模糊BusyBox。该指南与我们编写的所有模糊测试工具一起发布,作为我们模糊测试工作的一部分。我们希望社区能够进一步改进这些模糊控制,以便发现和修复BusyBox中的更多错误。
所有材料均可在Claroty的GitHub页面。
威胁分析
为了评估这些漏洞构成的威胁级别,我们检查了JFrog数据库中超过10,000个嵌入式固件映像(仅由公开可用的固件映像组成,而不是上传到JFrog Artifactory的固件映像)。我们发现,其中40%的漏洞包含一个BusyBox可执行文件,该文件与一个受影响的小程序相关联,这使得这些问题在基于linux的嵌入式固件中非常普遍。
然而,我们认为这些问题目前并不构成严重的安全威胁,因为:
- 利用DoS漏洞是微不足道的,但由于applet几乎总是作为单独的分支进程运行,因此影响通常会减轻。
- 利用信息泄漏漏洞是很重要的(请参阅下一节)。
- use-after-free漏洞可能被用于远程代码执行,但目前我们没有尝试为它们创建一个武器化的漏洞。此外,很少(而且本质上不安全)处理一个
awk来自外部输入的模式。
深入研究CVE-2021-42374 - LZMA OOB Read
Lempel-Ziv-Markov链算法(LZMA)与距离编码
LZMA是一种使用字典压缩的压缩算法,并使用范围编码器对其输出进行编码。字典压缩器使用复杂的字典数据结构找到匹配项,并产生文字符号和短语引用流,这些符号和短语引用由范围编码器一次编码一个比特,使用复杂的模型对每个比特进行概率预测。
压缩算法使用自适应二进制范围编码器将压缩流编码为位流。数据被分解成数据包,其中每个数据包描述单个字节或LZ77序列,其长度和距离隐式或显式编码。
. LZMA格式包含一个13字节的头,后跟LZMA压缩数据。下面是一个使用字符串“abc”压缩的小示例:
为了输出解压缩流,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;Bit = match_byte & 0x100;…
为了触发漏洞并控制我们将泄露数据的起始偏移量,我们需要确保满足以下条件:
Buffer_pos = 0
和
Rep0 = offset + dict_size
这种方式,pos将等于-(offset + dict_size)。后添加dict_size,pos将抵消所以我们可以通过match_byte从我们想要的偏移量中泄漏内存。泄露的内存很可能包含指针,这些指针可以进一步帮助攻击者进行利用活动(例如,通过促进ASLR绕过)。
导致越界访问
利用此漏洞的一般思路是准备一个专门制作的LZMA编码流,这样在解码时,两个条件都将被满足pos会等于一个负数吗抵消。最终,解压缩流将包含泄漏的内存,这些内存将被写入输出蒸汽。
满足第一个条件Buffer_pos = 0,我们需要确保我们的代码流程(state >= LZMA_NUM_LIT_STATES . state)在当前解压缩缓冲区流被刷新后到达,因此缓冲区指针位置将为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;Bit = match_byte & 0x100;Bit ^= (rc_get_bit(rc, prob + 0x100 + Bit + mi, &mi) << 8);/* 0x100或0 */ if (bit) break;} while (mi < 0x100);While (mi < 0x100) {rc_get_bit(rc, prob + mi, &mi);}
只要比特匹配我们的match_byte(泄露的字节),它就会在从Prob + 0x100 + bit + mi,但是一旦一个位不匹配,它就从问题+ mi。我们可以通过检查if来检测第一个不匹配的位是什么问题+ mi是通过写入更多的字面值字节来改变的,或者如果概率改变了,我们得到了不同的输出。最后,泄漏的位将被刷新到解压缩缓冲区中。
武器化ZIP文件
虽然这个漏洞是在LZMA解压缩算法中发现的,但我们发现许多applet支持LZMA压缩,并且默认情况下会尝试解压缩编码的LZMA流(参见“修复和解决方法”部分,了解控制此行为的配置标志)。例如,普遍使用的ZIP格式支持LZMA压缩作为“type 14”压缩。
从攻击者的角度来看,ZIP是一个更好的攻击媒介,因为:
解压缩的直接调用要常见得多unlzma。- 使用此攻击向量,对要解压缩的文件名没有限制(不像在tar攻击向量中,它需要一个
.lzma后缀)。 - 泄露的数据可以被提取并保存到文件中,以后可以远程读取。例如,这可能发生在允许上传带有媒体资源的zip文件的嵌入式web服务中,这些文件将被提取到可访问的位置。2022世界杯阿根廷预选赛赛程从那里,攻击者可以读取泄漏的内存数据。
为了测试这一点,我们构建了一个小的PoC脚本,生成一个武器化的ZIP,其中一个文件使用LZMA压缩:

修复和解决方案
BusyBox 1.34.0中的所有14个漏洞已被修复。直接下载链接),并敦促用户升级。
如果升级BusyBox是不可能的(由于特定的版本兼容性需求),BusyBox 1.33.1和更早的版本可以编译没有易受攻击的功能(applet)作为解决方案。
在运行使defconfig在BusyBox的源目录中(或者如果重用以前的配置),编辑config这样的文件:
男人。-取消注释CONFIG_MAN = ylzma-取消注释CONFIG_UNLZMA = y,CONFIG_FEATURE_SEAMLESS_LZMA = y和CONFIG_FEATURE_UNZIP_LZMA = y灰-取消注释CONFIG_ASH = y嘘-取消注释CONFIG_HUSH = yawk-取消注释CONFIG_AWK = y
致谢
我们要感谢来自BusyBox开发团队的Denys Vlasenko,他快速确认并修复了上述所有问题对于1.34.0版本。