😈CVE-2019-2215复现及分析
00 分钟
2023-6-19
2023-6-29
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
  • 下载payloads文件目录
  • 下载Android Studio,安装SDK
notion image
  • 安装模拟器
由于该漏洞受影响机型主要为以下机型,且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
  • 正常启动后即可运行模拟环境
notion image
将adb和emulator命令加入环境变量

搭建内核

可参考官网文档来构建指定版本的内核 ,Android内核代码是通过repo来进行管理的,所以先要安装repo
同步Android内核源码

0x3 漏洞复现

crash复现

用编译好的内核来启动模拟器
在终端可以看到ksan初始化
notion image
进入到exploit目录下,编译trigger.cpp这个触发漏洞的代码
notion image
进入模拟器的shell,运行漏洞程序
可以看到成功触发了漏洞,从打印的信息可以看到这是UAF漏洞
notion image

Root复现

qemu启动镜像
notion image
通过gdb运行root脚本,赋予sh root权限
notion image
可以看到此时在模拟器的终端上成功root:
notion image

0x4 漏洞成因分析

Google Project Zero提供了一个简单的PoC用于验证该漏洞:
整个Poc的流程清晰明了,可以概括为以下几个步骤:
  1. 打开binder 驱动;
  1. 创建一个epoll,并将binder fd加入到epoll中;
  1. 调用binder驱动的BINDER_THREAD_EXIT (释放掉binder thread结构)
该Poc运行在一般的内核上没有明显的效果,但是,在开启KASAN的内核上可以抓取到以下的日志:
通过KASAN的内核日志,可以看到虽然通过BINDER_THREAD_EXIT已经释放掉了内核中的binder_thread结构,但是在epoll中仍然链接了一个关于binder_thread的指针,因此,通过epoll其他的操作的时候即可触发UAF漏洞;
触发过程如图:
notion image

关于epoll

Epoll是Linux操作系统提供的一种 I/O 事件通知机制,用于高效管理大量的文件描述符。它是基于事件驱动的模型,用于监视文件描述符的输入和输出事件,并在事件发生时通知应用程序。
  1. epoll是select和poll的升级版,应用程序中调用 select() 和 poll() 函数, 使进程进入睡眠之前,内核先检查设备驱动程序上有无对应事件的状态,此时可通过查看 poll() 函数的返回值。
  1. 能够在返回值上使用的宏变量有以下组合:
    1. 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
编译内核
重新编译内核之后,用qemu启动,gdb连接
进入exploit目录,将poc编译送入模拟器中
notion image
在模拟器终端运行POC:
notion image
在gdb界面可以打印出以下信息:
notion image

0x5 漏洞利用

利用原理

Android的底层实现归根结底还是Linux,所以在Linux上的root方法在Android基本上也适用。Linux上一种常用的root方式:
接下来,我们继续分析实现提权的原理,整个提权的过程需要对task_struct这个结构体有个详细的了解。Linux内核是通过task_struct这个进程描述符的结构体来管理进程的,这个结构体包含一个进程所需的所有信息。而在Linux内部,每个线程又有一个task_struct来进行管理。其中,与root有关的是cred这个成员变量。
cred相当于链接这个进程的关卡,实际上就是相当于一个令牌,其跟root相关的成员变量是uidgid。一般来说,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

总结

CVE-2019-2215是一个存在于Android操作系统中的严重漏洞,影响Android 8.0至Android 10.0版本的操作系统。该漏洞存在于Android内核中的Binder组件中,它允许恶意应用程序在受影响的设备上获得特权提升,该漏洞允许攻击者通过向受害者设备发送特制的应用程序,实现在用户空间和内核空间之间的特权提升。攻击者可以利用漏洞获取系统级别的访问权限,并访问敏感的用户数据、执行恶意操作或潜在地控制受感染的设备,攻击者可以使用特制的应用程序,利用受影响的Android系统中存在的漏洞进行攻击。通过构造恶意的Binder调用序列,攻击者可以在特权级别上执行代码,绕过安全限制和隔离机制,从而导致设备被控制。
我想没有任何一个系统是百分百安全的,而安全行业也正是为此而生。

参考资料


评论
  • Twikoo