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
版本
- 下载payloads文件目录
- 下载Android Studio,安装SDK
- 安装模拟器
由于该漏洞受影响机型主要为以下机型,且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:
- 正常启动后即可运行模拟环境
将adb和emulator命令加入环境变量
搭建内核
可参考官网文档来构建指定版本的内核 ,Android内核代码是通过repo来进行管理的,所以先要安装repo
同步Android内核源码
0x3 漏洞复现
crash复现
用编译好的内核来启动模拟器
在终端可以看到ksan初始化
进入到exploit目录下,编译trigger.cpp这个触发漏洞的代码
进入模拟器的shell,运行漏洞程序
可以看到成功触发了漏洞,从打印的信息可以看到这是UAF漏洞
Root复现
qemu启动镜像
通过gdb运行root脚本,赋予sh root权限
可以看到此时在模拟器的终端上成功root:
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漏洞;触发过程如图:
关于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可以清楚的看到漏洞触发的函数调用关系,根据函数调用关系进行分析
编译内核
重新编译内核之后,用qemu启动,gdb连接
进入exploit目录,将poc编译送入模拟器中
在模拟器终端运行POC:
在gdb界面可以打印出以下信息:
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的运行日志:
总结
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 许可协议,转载请注明出处。