type
status
date
slug
summary
tags
category
icon
password
Property
Jun 29, 2023 03:08 AM
实验目的
成功部署实验环境,复现漏洞应用场景
分析漏洞成因,剖析实现原理
给出POC以及可参考的修复方案
0x0 实验环境
- Virtual Box 6.1
- Ubuntu 20.04
- Android Studio 2022
0x1 漏洞简述
CVE-2019-2215
是一个Google Project Zero团队发现的与binder驱动相关的安卓内核UAF漏洞,配合内核信息泄漏可以实现任意地址读写,进而可以通过权限提升获取一个root权限的shell。CVE-2019-2215
是有一个Android平台教科书级别的提权漏洞,Google Project Zero 针对该漏洞做了很详细的分析。如果手上有一台Pixel 2,刷入指定的4.4.177-g83bee1dc48e8
镜像,配合Jann Horn & Maddie Stone或是其他dalao们的exploit即可轻松复现;本EXP中使用的这种攻击方式构思极其巧妙,已经从最初的页表伪造 KSMA(Kernel Space Mirroring Attack) 进化到了一个全新的高度,利用Android的系统漏洞用来提权具备了极高的实战和分析价值。0x2 环境搭建
环境部署
- ubuntu18.04:8G内存+40硬盘+4核
- 安装python2.7的库
- 安装
gdb
- 查看
gdb
版本
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F4aa0ecc6-bdfa-4afa-a7a3-810a12f060b2%2FUntitled.png?table=block&id=b284820a-596c-4ca9-bda4-31bd66430994&t=b284820a-596c-4ca9-bda4-31bd66430994&width=2320&cache=v2)
- 下载payloads文件目录
- 下载Android Studio,安装SDK
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F48268fd7-ccc5-486c-9888-92755714fe2e%2FUntitled.png?table=block&id=c174433d-ffb2-45b2-b281-15448f5a2f36&t=c174433d-ffb2-45b2-b281-15448f5a2f36&width=1949&cache=v2)
- 安装模拟器
由于该漏洞受影响机型主要为以下机型,且Android大版本号位Android 10
1) Pixel 2 with Android 9 and Android 10 preview
2) Huawei P20
3) Xiaomi Redmi 5A
4) Xiaomi Redmi Note 5
5) Xiaomi A1
所以我们选择Google Pixel2:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6760ee80-2c00-45eb-aa01-c8d4e12f0a54%2FUntitled.png?table=block&id=e717c131-c37b-449f-9b0d-7b1ba66d8d09&t=e717c131-c37b-449f-9b0d-7b1ba66d8d09&width=1950&cache=v2)
- 正常启动后即可运行模拟环境
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F975e6a36-b2b4-4862-a649-79f6429b2ac3%2FUntitled.png?table=block&id=6a9827eb-157d-4d6a-bc27-4d781fd04da5&t=6a9827eb-157d-4d6a-bc27-4d781fd04da5&width=2432&cache=v2)
将adb和emulator命令加入环境变量
搭建内核
可参考官网文档来构建指定版本的内核 ,Android内核代码是通过repo来进行管理的,所以先要安装repo
同步Android内核源码
0x3 漏洞复现
crash复现
用编译好的内核来启动模拟器
在终端可以看到ksan初始化
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F944aa498-3263-44fe-8402-c0bdf18ac266%2FUntitled.png?table=block&id=32cba689-921d-46a3-87b1-2b9924d4706e&t=32cba689-921d-46a3-87b1-2b9924d4706e&width=1471&cache=v2)
进入到exploit目录下,编译trigger.cpp这个触发漏洞的代码
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6f91af1c-ecea-4f90-8f55-57f88b87edd1%2FUntitled.png?table=block&id=4395a9cd-215a-4486-91e7-895f22947eb2&t=4395a9cd-215a-4486-91e7-895f22947eb2&width=1628&cache=v2)
进入模拟器的shell,运行漏洞程序
可以看到成功触发了漏洞,从打印的信息可以看到这是UAF漏洞
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fda90b377-695e-469c-be09-9080139cf646%2FUntitled.png?table=block&id=a5f7b452-8b9c-42b1-9de5-f06382583adc&t=a5f7b452-8b9c-42b1-9de5-f06382583adc&width=1744&cache=v2)
Root复现
qemu启动镜像
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F380efce8-37d8-480f-afa5-bfe6ddfc3973%2FUntitled.png?table=block&id=90761f12-5f58-48eb-a199-61a6dc55718d&t=90761f12-5f58-48eb-a199-61a6dc55718d&width=2163&cache=v2)
通过gdb运行root脚本,赋予sh root权限
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ff3b9dcfc-d38c-46e9-b40b-0fe74fe31771%2FUntitled.png?table=block&id=5264a0c4-a28d-4a10-96d8-1477000bb1a4&t=5264a0c4-a28d-4a10-96d8-1477000bb1a4&width=1185&cache=v2)
可以看到此时在模拟器的终端上成功root:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fb7a4f148-52cd-473f-8fe7-ae209317d59f%2FUntitled.png?table=block&id=957a8a13-2e51-4265-9e25-69c882dc3faf&t=957a8a13-2e51-4265-9e25-69c882dc3faf&width=2462&cache=v2)
0x4 漏洞成因分析
Google Project Zero提供了一个简单的PoC用于验证该漏洞:
整个Poc的流程清晰明了,可以概括为以下几个步骤:
- 打开
binder
驱动;
- 创建一个
epoll
,并将binder fd
加入到epoll
中;
- 调用
binder
驱动的BINDER_THREAD_EXIT
(释放掉binder thread结构)
该Poc运行在一般的内核上没有明显的效果,但是,在开启KASAN的内核上可以抓取到以下的日志:
通过KASAN的内核日志,可以看到虽然通过
BINDER_THREAD_EXIT
已经释放掉了内核中的binder_thread
结构,但是在epoll中仍然链接了一个关于binder_thread
的指针,因此,通过epoll其他的操作的时候即可触发UAF漏洞;触发过程如图:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa9c4a4c0-8fb0-4bf7-86f6-e511fa521472%2FUntitled.jpeg?table=block&id=27088300-e9b1-4b50-94a2-c6381fc1628d&t=27088300-e9b1-4b50-94a2-c6381fc1628d&width=384&cache=v2)
关于epoll
Epoll是Linux操作系统提供的一种 I/O 事件通知机制,用于高效管理大量的文件描述符。它是基于事件驱动的模型,用于监视文件描述符的输入和输出事件,并在事件发生时通知应用程序。
- epoll是select和poll的升级版,应用程序中调用 select() 和 poll() 函数, 使进程进入睡眠之前,内核先检查设备驱动程序上有无对应事件的状态,此时可通过查看 poll() 函数的返回值。
- 能够在返回值上使用的宏变量有以下组合:
POLLIN, POLLPRI, POLLOUT, POLLERR, POLLHUP, POLLNVAL, POLLRDNORM, POLLRDBAND, POLLWRNORM, POLLWRBAND, POLLMSG, POLLREMOVE
这些值中使用最多的是下面几个组合:
· POLLIN | POLLRDNORM
表示可读· POLLOUT | POLLWRNORM
表示可写. POLLERR
表示出错通过Poc我们了解了epoll会持有
binder_thread
中的某个指针,网上Google几篇分析blog顺着梳理下源码,即可确定这个指针为binder_thread->wait
;当使用
ioctl
调用EPOLL_CTL_DEL
的时候,顺一下源代码,可以看到会触发一次__list_del
Unlink 原语
通过Poc我们了解了epoll会持有
binder_thread
中的某个指针,网上Google几篇分析blog顺着梳理下源码,即可确定这个指针为binder_thread->wait
;当使用
ioctl
调用EPOLL_CTL_DEL
的时候,顺一下源代码,可以看到会触发一次__list_del
函数调用栈分析
通过使用KSAN可以清楚的看到漏洞触发的函数调用关系,根据函数调用关系进行分析
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe6c1c31b-bf18-4898-882f-f55e330f3199%2FUntitled.png?table=block&id=c6d10bec-adb7-4d0e-b202-a7e4f684d137&t=c6d10bec-adb7-4d0e-b202-a7e4f684d137&width=1165&cache=v2)
编译内核
重新编译内核之后,用qemu启动,gdb连接
进入exploit目录,将poc编译送入模拟器中
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fcc6a4f42-dd37-4992-9bc0-72b5fd9f59a6%2FUntitled.png?table=block&id=cbd58ab2-130c-4181-985d-d4ffb4c8d520&t=cbd58ab2-130c-4181-985d-d4ffb4c8d520&width=1954&cache=v2)
在模拟器终端运行POC:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F27096f1e-8d1a-4efa-9b55-59dc93b24d36%2FUntitled.png?table=block&id=66b16a37-dd48-40e3-bef2-965cf0acd88e&t=66b16a37-dd48-40e3-bef2-965cf0acd88e&width=1062&cache=v2)
在gdb界面可以打印出以下信息:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fcc4ca386-3a76-460a-8203-af9a0e332102%2FUntitled.png?table=block&id=0c1f7403-44c1-46bd-b0f6-a6dd82959483&t=0c1f7403-44c1-46bd-b0f6-a6dd82959483&width=1200&cache=v2)
0x5 漏洞利用
利用原理
Android的底层实现归根结底还是Linux,所以在Linux上的root方法在Android基本上也适用。Linux上一种常用的root方式:
接下来,我们继续分析实现提权的原理,整个提权的过程需要对task_struct这个结构体有个详细的了解。Linux内核是通过task_struct这个进程描述符的结构体来管理进程的,这个结构体包含一个进程所需的所有信息。而在Linux内部,每个线程又有一个task_struct来进行管理。其中,与root有关的是
cred
这个成员变量。cred
相当于链接这个进程的关卡,实际上就是相当于一个令牌,其跟root相关的成员变量是uid
和gid
。一般来说,uid和gid表示的是这个进程的身份。对于拥有root权限的进程来说,uid为0为什么执行
commit_creds(prepare_kernel_cred(NULL));
会使得普通进程获取root权限,需要跟进到这两个函数来进行分析。- 首先是
prepare_kernel_cred(NULL)
,从函数中可以看到,当传入参数为NULL时,默认情况下会获取init_cred的cred
:
接着再来分析commit_creds这个函数,关键点就在将当前的进程的real_cred和cred设置为new中的值,而此时new的值和init_cred一样,也就是相当于将当前进程的cred提升为root级别
以下为成功利用漏洞实现提权获得root权限后的Android10的运行日志:
![notion image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F284a2c14-b811-43dc-a296-ddb1006fde2f%2FUntitled.png?table=block&id=ce547fbc-2c51-4198-86ee-8137184a6847&t=ce547fbc-2c51-4198-86ee-8137184a6847&width=1812&cache=v2)
总结
CVE-2019-2215是一个存在于Android操作系统中的严重漏洞,影响Android 8.0至Android 10.0版本的操作系统。该漏洞存在于Android内核中的Binder组件中,它允许恶意应用程序在受影响的设备上获得特权提升,该漏洞允许攻击者通过向受害者设备发送特制的应用程序,实现在用户空间和内核空间之间的特权提升。攻击者可以利用漏洞获取系统级别的访问权限,并访问敏感的用户数据、执行恶意操作或潜在地控制受感染的设备,攻击者可以使用特制的应用程序,利用受影响的Android系统中存在的漏洞进行攻击。通过构造恶意的Binder调用序列,攻击者可以在特权级别上执行代码,绕过安全限制和隔离机制,从而导致设备被控制。
我想没有任何一个系统是百分百安全的,而安全行业也正是为此而生。
参考资料
- 作者:百川🌊
- 链接:https://www.baichuanweb.cn/article/example-66
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。