影响Android多个高权限服务的严重漏洞详情披露(CVE-2018-9411)
媒体框架是安卓系统组件中经常被发现安全漏洞的组件,所以每次谷歌发布月度例行更新时经常会有它的身影。Google最近发现的媒体框架的漏洞是远程代码执行漏洞,攻击者可以制作特定的文件利用特权进程执行任意代码。目前Google已将其命名为CVE-2018-9411,危险等级定位危急,并在7月安全更新(2018-07-01补丁)中对其进行了修补,包括9月安全更新(2018-09-01补丁)中的一些附加补丁。
我还为此漏洞编写了一个概念验证利用,演示了如何使用它来从常规非特权应用程序的上下文中提升权限。
本文,我将介绍该漏洞和利用此漏洞的技术细节。首先我将介绍与漏洞相关的一些背景信息,然后再详细介绍漏洞本身。在介绍如何利用此漏洞的过程中,我将选择一个特定服务作为攻击目标,而不是受漏洞影响的其他服务。另外,我还将分析与漏洞相关的一些服务。最后,我将介绍我编写的概念验证漏洞利用的详细信息。
Project Treble
什么是Project Treble?简单的说就是谷歌为了整理安卓的碎片化,为了让手机厂商适配安卓版本更轻松,推出的新架构。
Project Treble对Android内部运作方式进行了大量更改,其中的一个巨大的变化是许多系统服务的分离。以前,Android服务包含AOSP(Android开源项目)和供应商代码。在Project Treble出现之后,这些服务会被分为一个AOSP服务和一个或多个供应商服务,称为HAL服务。更多背景信息,请点此。
HIDL
Project Treble的服务的分离增加了IPC(进程间通信)的量,以前在AOSP和供应商代码之间的同一进程中传递的数据,现在必须通过AOSP和HAL服务之间通过IPC。由于Android中的大多数IPC都要经过Binder,谷歌决定新的IPC也应该这样做。
但仅仅使用现有的Binder代码是满足不了新的IPC的,Google决定对其进行一些修改。首先,Google引入了多个Binder域,以便将这种新型IPC与其他域分开。更重要的是,他们引入了HIDL,这是一种通过Binder IPC传递的数据的全新格式。这种新格式由一组新的库支持,专用于AOSP和HAL服务之间的IPC新Binder域,其他Binder域仍使用旧格式。
与旧的HIDL格式相比,新HIDL格式的操作有点像层,新旧两种情况下的底层都是Binder内核驱动程序,但顶层是不同的。对于HAL和AOSP服务之间的通信,使用新的库;对于其他类型的通信,使用旧的库。这两种库包含的代码都非常相似,以至于新的HIDL库中某些原始代码会直接从旧库中复制到。虽然每个库的用法并不完全相同(你不能简单地用一个替换另一个),但它们仍然非常相似。
这两组库都以c++对象的形式表示Binder事务中传输的数据,从相对简单的对象(比如表示字符串的对象)到更复杂的实现(比如文件描述符或对其他服务的引用),这意味着HIDL为许多类型的对象引入了新的实现方式。
共享内存
Binder IPC的一个重要功能就是可以共享内存,为了保持简单性和良好性能,Binder将每个事务限制为最大1MB。对于进程希望通过Binder在彼此之间共享大量数据的情况,使用共享内存。
为了通过Binder共享内存,进程利用Binder的共享文件描述符的功能。使用mmap可以将文件描述符映射到内存,这允许多个进程通过共享一个文件描述符来共享同一个内存区域,常规Linux(非Android)的一个问题是,文件描述符通常由文件支持,如果进程想要共享匿名内存区域怎么办?出于这个原因,Android采用了Ashmem匿名共享内存机制,它允许进程在没有涉及实际文件的情况下分配内存,来备份文件描述符。
是否是通过Binder共享内存处理对象,是HIDL和旧库之间的一个区别。在这两种情况下,最终操作都是相同的,一个进程将ashmem文件描述符映射到其内存空间,通过Binder将该文件描述符传输到另一个进程,而另一个进程将其映射到自己的内存空间。不过,在处理对象的实现方式上是不同的。
在HIDL的情况下,共享内存的一个重要对象是hidl_memory,如源代码中所述:“hidl_memory是一种结构,可以用于在进程之间传输共享内存”。
漏洞介绍
让我们来看看hidl_memory的组成内容:
其中mHandle是一个句柄,它是一个HIDL对象,它包含文件描述符(在本文所举的样本中只有一个文件描述符)。mSize 表示要共享的内存大小,mName应该代表内存的类型,但是只有ashmem类型与此相关。
当通过HIDL中的Binder传输这样的结构时,复杂对象(比如hidl_handle或hidl_string)有自己的用于写入和读取数据的自定义代码,而简单类型(比如整数)则没有自定义代码。这意味着代码大小会被转换为64位整数,而在旧的库中,则使用32位整数。
这看起来很奇怪,为什么内存的大小应该是64位?为什么不像旧的库那样,用32位进程处理这个问题呢?让我们看一下映射hidl_memory对象(用于ashmem类型)的代码:
其中,没有任何关于32位进程的内容,甚至没有提到64位进程。
那其中到底发生了什么?mmap签名中的length字段的类型是size_t,这意味着它的位数与进程的位数相匹配。在64位进程中没有问题,一切都只是64位。另一方面,在32位进程中,大小被截断为32位,因此仅使用较低的32位。
这意味着,如果32位进程接收到大小大于UINT32_MAX(0xFFFFFFFF)的hidl_memory,则实际的映射内存区域将不够用。例如,对于大小为0x100001000的hidl_memory,内存区域的大小将仅为0x1000。在这种情况下,如果32位进程是基于hidl_memory大小执行边界检查,它们将会失败,因为它们将错误地表明内存区域跨越的范围超过整个内存空间,这就是漏洞。
寻找攻击目标
现在我们试着找到一个攻击目标,寻找符合以下标准的HAL服务:
1.编译为32位;
2.把对共享内存的接收作为输入;
3.在共享内存上执行边界检查时,不会截断大小。例如,以下代码不容易受到攻击,因为它对截断的size_t执行边界检查:
媒体框架是安卓系统组件中经常被发现安全漏洞的组件,所以每次谷歌发布月度例行更新时经常会有它的身影。Google最近发现的媒体框架的漏洞是远程代码执行漏洞,攻击者可以制作特定的文件利用特权进程执行任意代码。目前Google已将其命名为CVE-2018-9411,危险等级定位危急,并在7月安全更新(2018-07-01补丁)中对其进行了修补,包括9月安全更新(2018-09-01补丁)中的一些附加补丁。
我还为此漏洞编写了一个概念验证利用,演示了如何使用它来从常规非特权应用程序的上下文中提升权限。
本文,我将介绍该漏洞和利用此漏洞的技术细节。首先我将介绍与漏洞相关的一些背景信息,然后再详细介绍漏洞本身。在介绍如何利用此漏洞的过程中,我将选择一个特定服务作为攻击目标,而不是受漏洞影响的其他服务。另外,我还将分析与漏洞相关的一些服务。最后,我将介绍我编写的概念验证漏洞利用的详细信息。
Project Treble
什么是Project Treble?简单的说就是谷歌为了整理安卓的碎片化,为了让手机厂商适配安卓版本更轻松,推出的新架构。
Project Treble对Android内部运作方式进行了大量更改,其中的一个巨大的变化是许多系统服务的分离。以前,Android服务包含AOSP(Android开源项目)和供应商代码。在Project Treble出现之后,这些服务会被分为一个AOSP服务和一个或多个供应商服务,称为HAL服务。更多背景信息,请点此。 本文来自无奈人生安全网
HIDL
Project Treble的服务的分离增加了IPC(进程间通信)的量,以前在AOSP和供应商代码之间的同一进程中传递的数据,现在必须通过AOSP和HAL服务之间通过IPC。由于Android中的大多数IPC都要经过Binder,谷歌决定新的IPC也应该这样做。
但仅仅使用现有的Binder代码是满足不了新的IPC的,Google决定对其进行一些修改。首先,Google引入了多个Binder域,以便将这种新型IPC与其他域分开。更重要的是,他们引入了HIDL,这是一种通过Binder IPC传递的数据的全新格式。这种新格式由一组新的库支持,专用于AOSP和HAL服务之间的IPC新Binder域,其他Binder域仍使用旧格式。
与旧的HIDL格式相比,新HIDL格式的操作有点像层,新旧两种情况下的底层都是Binder内核驱动程序,但顶层是不同的。对于HAL和AOSP服务之间的通信,使用新的库;对于其他类型的通信,使用旧的库。这两种库包含的代码都非常相似,以至于新的HIDL库中某些原始代码会直接从旧库中复制到。虽然每个库的用法并不完全相同(你不能简单地用一个替换另一个),但它们仍然非常相似。
这两组库都以c++对象的形式表示Binder事务中传输的数据,从相对简单的对象(比如表示字符串的对象)到更复杂的实现(比如文件描述符或对其他服务的引用),这意味着HIDL为许多类型的对象引入了新的实现方式。
内容来自无奈安全网
共享内存
Binder IPC的一个重要功能就是可以共享内存,为了保持简单性和良好性能,Binder将每个事务限制为最大1MB。对于进程希望通过Binder在彼此之间共享大量数据的情况,使用共享内存。
为了通过Binder共享内存,进程利用Binder的共享文件描述符的功能。使用mmap可以将文件描述符映射到内存,这允许多个进程通过共享一个文件描述符来共享同一个内存区域,常规Linux(非Android)的一个问题是,文件描述符通常由文件支持,如果进程想要共享匿名内存区域怎么办?出于这个原因,Android采用了Ashmem匿名共享内存机制,它允许进程在没有涉及实际文件的情况下分配内存,来备份文件描述符。
是否是通过Binder共享内存处理对象,是HIDL和旧库之间的一个区别。在这两种情况下,最终操作都是相同的,一个进程将ashmem文件描述符映射到其内存空间,通过Binder将该文件描述符传输到另一个进程,而另一个进程将其映射到自己的内存空间。不过,在处理对象的实现方式上是不同的。
在HIDL的情况下,共享内存的一个重要对象是hidl_memory,如源代码中所述:“hidl_memory是一种结构,可以用于在进程之间传输共享内存”。
漏洞介绍
让我们来看看hidl_memory的组成内容:
无奈人生安全网
其中mHandle是一个句柄,它是一个HIDL对象,它包含文件描述符(在本文所举的样本中只有一个文件描述符)。mSize 表示要共享的内存大小,mName应该代表内存的类型,但是只有ashmem类型与此相关。
当通过HIDL中的Binder传输这样的结构时,复杂对象(比如hidl_handle或hidl_string)有自己的用于写入和读取数据的自定义代码,而简单类型(比如整数)则没有自定义代码。这意味着代码大小会被转换为64位整数,而在旧的库中,则使用32位整数。
这看起来很奇怪,为什么内存的大小应该是64位?为什么不像旧的库那样,用32位进程处理这个问题呢?让我们看一下映射hidl_memory对象(用于ashmem类型)的代码:
其中,没有任何关于32位进程的内容,甚至没有提到64位进程。
那其中到底发生了什么?mmap签名中的length字段的类型是size_t,这意味着它的位数与进程的位数相匹配。在64位进程中没有问题,一切都只是64位。另一方面,在32位进程中,大小被截断为32位,因此仅使用较低的32位。
这意味着,如果32位进程接收到大小大于UINT32_MAX(0xFFFFFFFF)的hidl_memory,则实际的映射内存区域将不够用。例如,对于大小为0x100001000的hidl_memory,内存区域的大小将仅为0x1000。在这种情况下,如果32位进程是基于hidl_memory大小执行边界检查,它们将会失败,因为它们将错误地表明内存区域跨越的范围超过整个内存空间,这就是漏洞。
寻找攻击目标
现在我们试着找到一个攻击目标,寻找符合以下标准的HAL服务:
1.编译为32位;
2.把对共享内存的接收作为输入;
3.在共享内存上执行边界检查时,不会截断大小。例如,以下代码不容易受到攻击,因为它对截断的size_t执行边界检查:
本文来自无奈人生安全网