导语:我最近在Alpine Linux的软件包管理器中发现了两个关键的漏洞,分别是CVE-2017-9669和CVE-2017-9671,如果你正在使用Alpine Linux,这两个漏洞可能会导致攻击者在你的计算机上执行恶意代码。

1498462846275011.jpg

我最近在Alpine Linux的软件包管理器中发现了两个关键的漏洞,分别是CVE-2017-9669和CVE-2017-9671,如果你正在使用Alpine Linux,这两个漏洞可能会导致攻击者在你的计算机上执行恶意代码。

Alpine Linux是一个面向安全应用的轻量级Linux发行版。它采用了musl libc和busybox以减小系统的体积和运行时资源消耗,同时还提供了自己的包管理工具apk。Alpine Linux的内核都打了grsecurity/PaX补丁,并且所有的程序都编译为Position Independent Executables (PIE) 以增强系统的安全性。

在过去几年中Alpine Linux越来越受欢迎,这主要是因为它在容器内使用,特别是在Docker中。大多数官方Docker存储库都具有Alpine 版本,而Alpine存储库本身也有超过一千万次的使用频率。

Alpine Linux是一个面向安全的轻型的Linux发行版,关键的是,相比于其他Linux的Docker镜像,它的容量非常小,仅仅只有5MB。为了实现这些目的,其开发人员付出了大量的努力,例如,通过包括内核方面的防御机制,并通过编译所有现代二进制保护的用户空间包。正是由于Alpine Linux的这些优势,我们在Twistlock中使用Alpine,Twistlock 的创建目的就是扫描容器,对照CVE数据库检查容器中的软件。此外,它还会检查容器环境,比如,如果容器不应该在第一时间连接网络,那么它就会断开网络连接。

作为安全研究员,我决定探索一下Alpine的内部组成,并寻找可能危及所有Alpine用户的重大漏洞。

定位apk并查找错误

由于Alpine提供了自己的包管理工具apk,所以我决定重点探索一下它。如果我以某种方式在安装之前修改其程序包,或让程序包管理器降级为程序包,我就可以在目标系统上执行代码了。

经过一些初步研究,我最终决定尝试模糊特定部分的apk。于是我修补了apk,并进行了一些修改,并为afl编译(确切地说,我写了我自己的applet,使用一个文件作为输入)。过去我经常通过使用afl来解决零日漏洞,所以我决定使用该方法,通过模糊假设的潜在易受攻击的特定功能来找到apk中的漏洞。

由于我写的小程序专门针对于tar解析代码,所以利用 apk接受gzip压缩tarballs(tar.gz)的更新文件,我分离出了一个tar流(tar-stream),并给了它一个文件的代码。应该说,这是一个完美的模糊点,有很多代码来处理解析用户输入,任何程序的崩溃都应该发生在签名过程之前。为了方便比较,解析特定包中的崩溃将不太重要,因为apk会检查文件签名。

不到一天的时间,我的apk小程序中就发现大量的崩溃。我开始调试崩溃并很快找出了漏洞,我在tar解析函数中发现了两个可能导致堆溢出的代码。

两个漏洞的描述

溢出可能发生在以下行中,这些行来自archive.c:

1.jpg

首先,让我们了解上下文。代码片段来自archive.c中的函数apk_parse_tar。此函数接收一个apk_istream的tar流,经过解析它,并在每个已解析的代码块( block)上运行一个回调函数。

一般来说,tar流由512字节的代码块组成,从文件数据块之后的tar头代码块开始。其中一个标题字段是一个typeflag,表示以下文件的类型。它还用于指示使用特殊代码块,例如longname或“GNU long name extension”标志,这意味着下一个字节包含随后文件的名称且当文件名长度大于100字节时使用。

所以当解析器遇到一个longname代码块时,它应该分配给定大小的缓冲区,并将该名称从流中复制过来。这个缓冲区是longname,如果需要,blob_realloc也可用于扩展缓冲区大小的函数。

我们来看看blob_realloc:

2.jpg

关于这个函数的令人烦恼的事情是它接受一个int类型的大小,这个大小是自然签名的。 b-> len是long类型,这意味着它也被签名。

尝试模拟任何大小大于0x80000000的情况是菲常有用的,0x80000000是2147483648作为无符号int和-2147483648作为签名的int。换句话说,当大小大于最大有符号int大小时,它将被视为负数,所以blob_realloc返回0时,可以不用修改缓冲区。

在以下调用is-> read中,大量的字节将被复制到缓冲区,溢出其分配的大小并覆盖堆上的任何后续数据。只要读取函数将大小视为无符号,并且在tar.gz的情况下,该函数是来自gunzip.c 的gzi_read,其目标为size_t(无符号)。

还值得一提的是,将blob_realloc定义更改为接受size_t而不是int是不足以解决此问题的,因为当向最大entry.size添加1时可能会发生整数溢出,这将发生缓冲区溢出。

可以利用这种缓冲区溢出来实现代码执行,攻击者可以通过将堆上的函数偏移量覆盖到具有参数的任何函数上来预测执行时的内存布局。虽然我还没有发布我的PoC,但是我已打算在不久的将来写下这个开发过程,一旦这个漏洞被修正了,就不可能在野外被利用,MITR已经把此漏洞定义为了CVE-2017-9669。而CVE-2017-9671则可以在处理tar pax标头的代码中找到对blob_realloc的另一个调用,其中缓冲区溢出可能以相同的方式发生。

攻击范围

这些漏洞是可以利用这些特定缓冲区溢出的方式,显而易见的是尝试在系统上实现代码执行。攻击的唯一先决条件是找出程序的内存布局,所以像ASLR这样的保护措施可能会阻止攻击者成功的进行攻击,但攻击者可能会绕过它,仍然可以执行。

实际的攻击情形将是攻击者通过制作恶意的APKINDEX.tar.gz文件(Alpine的更新文件)并将其托管在他的HTTP服务器上。不管该设备是否包含容器,网络上的任何用户都可以在任何设备中运行apk更新或基于Alpine(调用后面的命令)构建容器映像,这就造成了攻击者的恶意代码将在受害者的设备上执行。攻击者可以执行隐藏攻击的代码,这样受害者可能永远都不知道他的设备是否被盗用。

1498462996924602.png

2.5.0_rc1之后的所有版本的apk都容易受到这个两个CVE的攻击。而且我已经查看了旧的代码,似乎旧版本也可能会遇到类似的问题。

应对方案

我已告知Alpine的开发商这两个漏洞,并与他们一起合作发布了一个快速修复的补丁。

除此之外,开发商还提到要为apk增加了一些额外的强化功能,这可能会进一步限制攻击者利用这种和类似的漏洞,如控制流完整性。

源链接

Hacking more

...