这个漏洞是位于Binder Driver内核空间与用户空间的client和server通信时,不同线程同步竞争调用binder_ioctl()造成的use_after_free漏洞。
一、漏洞原因
1.Binder简介
Binder机制是Android采用的进程间通信机制,采用了C/S架构。Client进程通过RPC与Server通信,可以简单地划分为三层,驱动层、IPC层、业务层。demo()方法是Client和Server共同协商好的统一方法;handle、RPC数据、代码、协议这4项组成了IPC层的数据,通过IPC层进行数据传输;而真正在Client和Server两端建立通信的基础设施便是Binder Driver。
Binder driver没有直接操作硬件,只是对设备内存进行处理。主要是驱动设备的初始化(binder_init),打开(binder_open),映射(binder_mmap),数据操作(binder_ioctl)。
例如,当用户空间调用ioctl()方法时,通过系统调用__open()方法,最终调用binder驱动的binder_ioctl()方法。
Binder通信模型如下:
Binder协议包含在IPC数据中,分为两类:
BINDER_COMMAND_PROTOCOL: Binder请求码,以“BC_”开头,用于从IPC层传递到binder driver层;
BINDER_RETURN_PROTOCOL: binder响应码,以“BR_ ”开头,用于从binder driver层传递到IPC层;
Binder IPC通信至少是两个进程的交互:
- client进程执行binder_thread_write,根据BC_XXX命令,生成相应的binder_work;
- server进程执行binder_thread_read, 根据binder_work.type,生成BR_XXX,发送到用户空间处理;
2.漏洞原理
Server进程收到Client请求时,会进入内核,调用“binder_alloc_new_buf()”从Client进程对应的“alloc->free_buffers.rb_node”中申请一个“struct binder_buffer”对象,被申请的对象会从“alloc->free_buffers.rb_node”中移除,并链入“alloc->allocated_buffer.rb_node”。然后,为了避免“t->buffer”在使用时被释放,将“t->buffer->allow_user_free”赋值为0。
Client进程收到Server进程发来的消息后,就会结束本次交互,释放“t->buffer”,销毁Parcel对象。攻击者可以构造满足内核校验的参数,主动向内核发送“BC_FREE_BUFFER”请求,以提前释放该“t->buffer”对象。
从上图可知,buffer->allow_user_free是0时,Client无法释放“buffer”对象,否则将调用“binder_alloc_free_buf()”释放“buffer”。
如果Client进程能在Server进程将““t->buffer->allow_user_free”赋值为0之前就触发到“binder_alloc_free_buf()->binder_free_buf_locked()->rb_erase()”,就有可能将其从“alloc->buffers”中移除,之后再选择合适时机触发kfree()将其释放。此时当Server进程继续使用“t->buffer”时就触发了use_sfter_free问题。
这个漏洞的产生是由于2016年11月的一个补丁,将原先效率较低的保护“binder_ioctl()”的全局互斥锁优化为更加细粒度的互斥锁。
二、漏洞利用
EXP地址: https://github.com/jltxgcy/CVE_2019_2025_EXP
1、提前分配binder_buffer,以供后面释放;
2、构造出:Client执行BC_FREE_BUFFER,Server进程执行BC_REPLY(binder_alloc_new_buffer),并启动两个线程,设置竞争;
3、堆喷,实现任意地址写,向内存中写入提权脚本并执行。
由于构造Client执行BC_FREE_BUFFER和Server进程执行BC_REPLY时使用了很多framework层的接口,因此EXP需要在android源码环境下编译。
编译运行结果待续。。。。