BlueBorne远程代码执行漏洞Poc实战(CVE-2017-0781)

发布者:freakish
发布于:2017-12-12 11:48

BlueBorne远程代码执行漏洞Poc实战(CVE-2017-0781)

  • 前几天,一个名为Armis的公司发布了Android设备上的一个蓝牙远程代码执行漏洞(CVE-2017-0781)的Poc,漏洞命名为BlueBorne,尽管BlueBorne漏洞涉及到了8个漏洞点,但是这个Poc只用了其中的2个就达到了利用的目的。
  • 整个利用过程分为2个阶段,Poc先是使用了内存泄露漏洞(CVE-2017-0785)获取内存地址并且绕过ASLR保护,通过这个手段就可以顺畅的调用libc.system函数并且在手机设备上执行代码,在这个例子中最后就是得到一个反弹Shell。
  • Armis公司发布的Poc是针对搭载了Android7.1.2系统的Pixel和Nexus 5X 手机,如果要把Poc代码移植到其他机型上,只需要修改相应的libc和bluetooth的偏移即可。
  • 本文稍后会说一下,在其他机型上也可以使用这个Poc,就是比较麻烦,比如在6.0.1机型上测试这个Poc就比较麻烦,一个是利用过程复杂了,另外一个Poc需要修改的地方也多一些。
  • 在进行下面的步骤之前,请先确保你的手机已经root

下载相关的库文件

  • 第一步是从手机上把需要分析的库文件下载下来,稍后要使用IDA或者Radare进行分析,请参考下面的命令:
    1. $ adb pull /system/lib/hw/bluetooth.default.so
    2. $ adb pull /system/lib/libc.so

libc.system函数

  • 使用Radware打开libc.so然后寻找system这个函数,我这里的地址是0x3ea04,这里改下Poc中相关变量 LIBC_TEXT_STSTEM_OFFSET = 0x3ea04 +1

内存泄露

  • 通过内存泄露这个漏洞我们可以知道libc.so和bluetooth.default.so的加载位置
  • 在我们分析的这个机型中,我们所需要的几个关键点在内存中的地址并不是固定不变的,所以我们需要在内存中寻找出这些关键位置,然后我们就可以依据这些位置信息进一步修改利用代码:
  • 因为Android进程每次重启之后上述的地址值都会发生改变,所以为了方便,我们在开始之前需要先对com.android.bluetooth.process 进程做一个内存镜像,可以参考下面的命令进行操作:
  • 这里我们在泄露的内存段中我们搜索一个取值范围在0xb376f000和0xb38b5000之间的一个数值,为了省事,我直接使用现成的脚本(CVE-2017-0785.py)来操作:
  • 现在搜索有了结果,我这里使用 0xb38b3d80(180行) ,使用这个值我们计算出偏移值,然后更新BLUETOOTH_BSS_SOME_VAR_OFFSET这个变量,并注意同时更新搜索结果的那个数据源(原文不太确定:without forgetting also to update the element of the result table from which we have obtained this value)。
  • 下面我们接着来看下怎么获取libc的加载地址:
  • 在上面的搜索结果中选取任意一个值,然后计算出偏移并更新变量LIBC_SOME_BLX_OFFSET
  • 到这里为止,基本上就可以不用去管ASLR保护了

小技巧

  • 我这里推荐一个小脚本,可以打印泄露的变量 result 的内容:
  • 或者还有一个方法可以尝试,就是你可以尝试多做几次内存快照,然后对这几个内存快照进行对比,找到其中几处内存值不变的几个点作为参考点来进行相对定位,这也是一个不错的方法,我直接上图:

REMOTE_NAME变量

  • 这个变量包含了建立蓝牙连接的设备名称,在7.1.2版本的Poc里面,使用这个变量来存放system函数的地址和Bash命令行,有关这个变量的细节我们后面再说。
  • 我这里使用包含PEDA-ARM和searchmem组件的GDB来获取这个变量的内存地址,最后计算出来的偏移地址保存在BSS_ACL_REMOTE_NAME_OFFSET中,我给出我的操作示意图:

攻击载荷(Payload)

  • 从Armis公司的Poc技术文档(https://go.armis.com/hubfs/BlueBorne - Android Exploit.pdf)细节中我们可以知道,如果我们使用REMOTE_NAME的值来覆盖R0, btu_hci_msg_process这个函数将会跳转到[REMOTE_NAME+8]的位置,而不是去执行R0指向的位置,请看下面这段代码:
  • 这样一来,我们可以把system函数的地址放到REMOTE_NAME+8的位置,然后REMOTE_NAME开始的位置放上要执行的BASH命令,但是这样就有一个问题,我们的system函数地址插在了命令的中间去了,这样命令就会报错了。Armis给出来这样的解决办法,就是把要执行的命令用分号分成2条,前面一条里面包含了system的地址,后面一条包含了完整的bash命令,这样前面的那条命令报错就让他报错好了,目的我们达到了,最终的结果是这样的:
  • 但是,如果你的测试环境是Android6.0.1,你再按照上面的步骤过一遍就发现不行了,因为库函数里面没有上述那些函数。但是也不用放弃,因为我发现在可溢出的函数里面,也有可以通过R0来控制执行流程的函数,这里我选择000f1e36处的函数,看图:
  • 通过下面这些指令组,我们就可以通过R0来控制跳转:
  • 代码简化一下,就像这样:
  • 为了达到我们的目的,我们这里就需要三个指针来控制跳转,一个指针来控制R0,而上面的那个方法只需要一个system函数地址就行了,好了,来看下REMOTE_NAME中可以存放的Payload的结构吧:

执行测试

  • 上面的这些工作全部做完之后,我们就可以来测试了,注意,为了达到测试效果,有时候我们需要多次执行测试程序才能达到漏洞利用的效果:

相关代码

致谢

译者


声明:该文观点仅代表作者本人,转载请注明来自看雪