03月04, 2019

“水滴”来袭:详解Binder内核通杀漏洞

作者: Hongli Han(@hexb1n) of Qihoo 360 C0RE Team

前言

Binder是基于OpenBinder实现的,是Android系统的重要组成部分。Binder构建于Linux内核中的Binder驱动之上,系统中涉及到Binder通信的部分,都需要通过与Binder驱动交互来实现数据传递。由于Binder驱动在整个Android系统中发挥的重要作用,一直以来也是Android安全研究的重点之一。

在二进制的世界里,对象的生成和销毁都有一定的流程和时间点,有一些是在编译器层面来实现,有一些却需要程序设计者来维护。一旦这个流程设计的不够完美,使得攻击者能够通过非法操作扰乱其正常的生命周期便有可能造成一系列的安全问题。去年8月份我在对Binder驱动代码进行安全审计的时候,发现了一枚如同《三体》中“水滴”一般的内核通杀漏洞,拥有了惊人的破坏力,仅用一个漏洞便可以实现任意地址读、任意地址写、写任意内容、信息泄露。同时,Binder驱动也是目前为数不多的几个可被沙箱中的进程访问的驱动之一,该漏洞可能被用于沙箱逃逸。在如此重要的内核驱动中会潜伏这样一枚通杀漏洞堪称神奇。

基于这个漏洞,我们实现了对Pixel全系手机的ROOT,其中的Pixel 3也代表了谷歌安卓内核目前最高的安全防御水平,这也是Pixel 3自问世以来,全球范围内首次公开的ROOT攻击。这里要感谢@周明建@王晓东@姚俊@邵大成等团队小伙伴的支持,让漏洞利用能够及早的完成,文末也附了我们的提权视频链接[1]。

这个漏洞在2019年3月的Android Security Bulletin中已经公开,对应的漏洞编号为CVE-2019-2025。下文我将会介绍该漏洞危害、影响范围、漏洞原理以及利用思路。

漏洞危害及影响范围

漏洞危害

1) 通杀。目前国内外主流的Android机型基本都会受到影响;

2) 攻击能力极强。该漏洞可实现较稳定的任意地址读写、写任意内容、信息泄露,并且每触发一次漏洞便可以任意写一次、读一次,Google现有的内核安全缓解措施对于这类能够任意地址读写的漏洞暂无有效的防御策略;

3) 沙箱逃逸。可能用于沙箱逃逸,并直接提权到ROOT;

同时,Binder驱动已早在2015年初被合入Linux主线,使用了Binder模块的平台均有可能受到影响。

影响范围

该漏洞属于use-after-free问题,触发时需要不同线程间同步竞争调用”binder_ioctl()”,而在早期的设计中,”binder_ioctl()”由一个效率较低的全局互斥锁保护,见图1。

image.png

图1

而此问题后续被优化,从”drivers/android/binder.c”的commit日志可以看到,2016年11月14日的一个补丁将这个全局互斥锁去掉,并优化为更加细粒度的互斥锁来保护,见图2。完整的补丁可参见链接[2]。

image.png

图2

打上这个补丁的内核源码便可能受到该漏洞的影响。

由于该漏洞具备通杀能力,目前市面上主流在用的2016年11月之后的内核版本多数都会受到影响,在修补该问题之前将会有大量的设备处于安全风险之中。成功ROOT后攻击者可以获得系统的最高权限,同时该漏洞可能被用于远程攻击链,若是被黑产利用将可直接对用户的个人隐私、财产安全甚至人身安全造成严重的危害。目前Linux主线上已提供了针对该漏洞的补丁,Android厂商可参考附注链接[3]及时修补。

漏洞的成因

基础知识

关于Binder机制这里就不做过多介绍了,接触过Android的同学应该对它或多或少都有一定的了解。理解该漏洞需熟悉通过Binder通信的双方的基本交互流程,以及中间用到一些结构体对象,网络上关于Binder的资料非常丰富,可自行补充。

漏洞原理

当用户进程通过调用"IPCThreadState::transact()"向server进程请求数据时,server进程会调用”IPCThreadState::sendReply()”向用户进程回传数据以作为响应。在这个过程中,server进程会陷入内核,并调用“binder_alloc_new_buf()”从用户进程(“target_proc->alloc”)对应的”alloc->free_buffers.rb_node”红黑树中申请一个”struct binder_buffer”类型的对象,被申请得到的对象会从”alloc->free_buffers.rb_node”红黑树中移除,并链入到”alloc->allocated_buffers.rb_node”红黑树中进行维护,此后将”t->buffer->allow_user_free”赋值为0,以避免”t->buffer”在使用过程中被释放,见图3。

image.png

图3

用户进程拥有对该”t->buffer”的释放权,不过要在用户进程收到了server进程发来的消息,结束本次交互并销毁所用的Parcel对象时。然而,我们可以试图通过主动向内核发送”BC_FREE_BUFFER”请求来提前释放该”t->buffer”对象,不过这需要满足内核对各项参数的校验,如图4所示。

image.png

图4

上文中提到的“t->buffer”可以通过向内核传入对应的“data_ptr”值,再通过调用“binder_alloc_prepare_to_free()”函数来找到,其返回值会赋值给”buffer”,紧接着内核会检查“buffer->allow_user_free”以及”buffer->transaction”的合法性,由于缺少互斥锁的保护,这里存在一个条件竞争问题,如果用户进程能在图3中”t->buffer->allow_user_free”被赋值为0之前触发到“binder_alloc_free_buf()->binder_free_buf_locked()->rb_erase()”,便有可能将其从”alloc->buffers”中移除,见图5。

image.png

图5

之后便可再选择合适时机触发”kfree()”将其释放,而此时当server进程继续使用”t->buffer”时便触发了use-after-free问题。这样我们就可以借助堆喷技术来实现任意地址读写以及信息泄露。

漏洞利用

内核中每年公开的漏洞数量都多达数百个,但真正能够成功提权的寥寥无几。而近年来随着系统防护的不断完善,此前一些可以用来ROOT的漏洞,如果处在现有的防护机制下也变的无能为力。在Android的通用模块出现这类具备了任意地址读写、信息泄露能力,同时还可能用于沙箱逃逸的漏洞十分少见。即便随着Android系统后续一些新的防护机制引入,这类漏洞仍有可能具备很强的攻击潜力。由于漏洞的特点,攻击手法也是仁者见仁智者见智,我们也做出来几种不同的利用方案,这里会介绍漏洞利用的基本思路,具体的细节这里不会放出。

任意地址写

调用合适的堆喷函数去占位该”t->buffer”对象,堆喷成功后,图3中3178行所示的"t->buffer->data"可由攻击者完全控制,而"tr->data.ptr.buffer"是server进程发给用户进程的reply数据,可由攻击者间接控制。当“copy_from_user()”函数被执行时,便触发了任意地址写问题。

任意地址读

server进程此后又会调用“binder_enqueue_thread_work_ilocked()”函数向用户进程发送消息,如图6中3377行所示。

image.png

图6

与此同时,用户端进程在循环调用“IPCThreadState::talkWithDriver()”等待server进程的响应。当有消息到达时,内核会通过调用图7中4100, 4107行所示函数,将server进程发送过来的“struct binder_transaction”类型的对象取出,并保存在变量”t”中,其中“t->buffer”是被我们控制的恶意对象,而"target_node"是”struct binder_buffer”结构体的一个成员变量,若将其设置为非空值,将会被当成”struct binder_node”类型的指针,并从该指针加0x58、0x5c位置取值赋值给”tr.target.ptr”及”tr.cookie”。此后内核再调用4319行所示的”copy_to_user()”将数据传递给用户进程。通过这一机制我们便可以实现任意地址读。

image.png

图7

信息泄露

通过寻找一些带有敏感信息的结构体对”t->buffer”进行堆喷,“t->buffer->target_node”, “t->buffer->data_size”, “t->buffer->data”都将作为信息泄漏点,将堆喷结构体中的敏感数据泄露给用户进程。

时间节点

  • 2018-08月份发现该漏洞,确认了漏洞危害及影响范围;
  • 2018-09-28提交至Google;
  • 2018-10-06 Google回复邮件,进一步确认问题细节;
  • 2018-10-23 Google确认该问题;
  • 2018-11-02 提交漏洞利用至Google;
  • 2018-11-06 Linux kernel主线上修复该问题;
  • 2018-12-18告知漏洞公开时间,并多次在邮件中致谢;
  • 2019-03-05安全公告,漏洞编号为CVE-2019-2025;

image.png

我们是全球首个发现该漏洞并提交至Google的安全团队,同时由于漏洞本身的严重性,并且我们成功利用这一漏洞绕过了代表谷歌安卓目前最高水平的内核防护机制,完成了针对Google旗下三款Pixel系列机型的完美ROOT,也收到了Google诚挚的致谢。

image.png

总结

漏洞在原理上拥有极强的攻击能力,但在实际利用过程中还是有一定的门槛,需要非常熟悉漏洞利用技巧及内核的相关知识才能将其稳定的利用,我们在Pixel系列设备上能够实现近100%的漏洞触发成功率。在Android系统安全防护日臻健全的时代,这类通杀漏洞更是具备了稀缺性,也是黑产从业者梦寐以求的,安全研究人员如果不能赶在他们之前发现并修补该漏洞,一旦被黑产从业者掌握并大规模利用,造成的损失将难以估计。各家Android厂商也需尽快修复该问题,避免用户暴露在安全风险之中。

参考

[1]https://weibo.com/tv/v/HaeCNbLmz?fid=1034:4324393006868015

[2]https://lore.kernel.org/patchwork/patch/805040/

[3]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7bada55ab50697861eee6bb7d60b41e68a961a9c

本文链接:http://blogs.360.cn/post/Binder_Kernel_Vul_CH.html

-- EOF --

Comments