Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现

admin 2022年11月13日15:45:51评论44 views字数 3456阅读11分31秒阅读模式
漏洞概述


2020年10月,谷歌安全研究人员披露了三个Linux内核蓝牙协议栈漏洞,可导致远程代码执行,被称为BleedingTooth。这三个漏洞中,一个是堆溢出,编号为CVE-2020-24490;另一个是类型混淆,编号为CVE-2020-12351,最后一个是信息泄露,编号为CVE-2020-12352。近日,谷歌安全研究人员又披露了BleedingTooth中CVE-2020-12351和CVE-2020-12352组合的漏洞利用及细节,并在蓝牙4.0下,实现了零点击远程代码执行。


漏洞分析


CVE-2020-12351


该漏洞出现在net/bluetooth/l2cap_core.c中。l2cap_recv_frame()是解析和处理l2cap协议数据包的函数。代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


获取通道cid和l2cap数据包长度len。代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


根据不同的通道cid,进入不同的子过程进行处理,进入l2cap_data_channel()函数。代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


首先,通过cid找到通道chan;如果没有找到,判断cid是否为L2CAP_CID_A2MP;如果是,调用a2mp_channel_create()创建一个新的通道chan。a2mp_channel_create()函数实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


调用amp_mgr_create()创建mgr,在amp_mgr_create()函数中,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


调用a2mp_chan_open()创建通道chan,该函数将初始化一部分数据,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


如将chan->mode初始化为L2CAP_MODE_ERTM。chan->data赋值为mgr,类型为struct amp_mgr。成功创建a2mp通道返回到l2cap_data_channel()中,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


根据chan->mode的不同,进入不同的data处理子过程,当mode为L2CAP_MODE_ERTM和L2CAP_MODE_STREAMING时,进入l2cap_data_rcv()函数中,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


该if条件中,会调用sk_filter()函数,此时chan->data为参数。而sk_filter()函数定义如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


第一个参数类型为struct sock,而chan->data类型为struct amp_mgr,发生类型混淆。


CVE-2020-12352


该漏洞是出现在a2mp协议中,漏洞代码位于net/bluetooth/a2mp.c,多个函数使用未初始化的结构体,将数据返回到用户层,导致信息泄露,可泄露内核栈上的内存数据。漏洞原理较为简单,以a2mp_getinfo_req()函数为例,该函数是响应getinfo请求时调用的,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


行304,通过req->id获取hdev,如果不存在hdev或hdev->type不是HCI_AMP,进入if语句中,定义struct a2mp_info_rsp类型的 rsp,该结构体定义如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


其只使用了rsp.id和rsp.status,其他的数据域未使用也未初始化,可以泄露16字节数据,然后调用a2mp_send()函数将响应包发送到用户层,泄露内存数据。

CVE-2020-24490


该漏洞只能在bluetooth 5.0下触发,在bluetooth 5.0之前,HCI进行广播的最大数据长度为0x1F,0x20-0xFF保留。如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


在bluetooth 5.0中,该length最大扩展到229字节。如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


该漏洞代码位于net/bluetooth/hci_event.c中,在处理HCI_LE_Extended_Advertising_Report事件中,未判断广播数据长度最大值,后续拷贝广播Data导致溢出。调用过程如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


process_adv_report()函数处理广播数据,将广播数据拷贝到发现的设备中,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


调用store_pending_adv_report()函数,该函数实现广播数据拷贝,代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


其中,discovery_state结构体定义如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


last_adv_data数据大小为HCI_MAX_AD_LENGTH,共31字节,当执行memcpy时发生溢出。


利用分析与复现


控制代码执行流程


前文分析到CVE-2020-12351类型混淆是在sk_filter()函数中发生的,sk_filter()函数调用sk_filter_trim_cap()函数,该函数代码实现如下:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


该函数第一个参数为sk,参数类型为sock结构体,这部分代码中对sk和skb的检查容易绕过。接下来关键代码如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


行113,对sk->sk_filter进行解引用,如果成功获取filter指针,进入行115。行119,调用bpf_prog_run_save_cb()函数,参数分别为filter->prog和skb,该函数代码实现如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


然后,行676,调用__bpf_prog_run_save_cb()函数,该函数实现代码如下:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


接着,行662,调用BPF_PROG_RUN(prog,skb),该函数定义为一个宏,实现代码如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


一路调用下来,最终会调用到红框中的代码,简化一下调用过程为:

sk->sk_filter->prog->bpf_func(skb, sk->sk_filter->prog->insnsi)。因此,只要控制sk->sk_filter就可以控制执行流程。


堆喷占位


函数sk_filter()的第一个参数类型为struct sock,而实际传入的参数类型为struct amp_mgr,可以采用堆喷128大小的内存块进行占位,伪造amp_mgr 对象。这里有个问题,sk->sk_filter在sock中的偏移为0x110,而amp_mgr结构体大小为0x70,偏移已经超出了范围。要解决这个问题,这里可以采用如下巧妙的堆喷布局:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


结构体amp_mgr在kmalloc-128类型的slub中被分配,从第三个块开始,amp_mgr结构体偏移0x10处,可以被伪造成sk_filter,便可以满足sk对sk_filter域的解引用,并且可控。


布局载荷


通过堆喷占位控制代码执行流程后,接下来就是布局攻击载荷。可以采用堆喷1024大小的内存块去伪造l2cap_chan对象,因为结构体大小为792,正好落在kmalloc-1024 slub块中,而且a2mp通道也属于l2cap通道中,释放a2mp通道时,l2cap通道也将被释放,操控起来较为灵活,最终布局如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


泄露l2cap_chan对象地址


通过堆喷布局和创建释放l2cap_chan通道等一系列操作后,可能存在一个指向kmalloc-1024内存块地址的l2cap_chan对象,可以通过CVE-2020-12352漏洞泄露一个内核栈上面的内核地址,如下图中红框所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


通过该内地地址减去一个0x110偏移便可以找到一个l2cap_chan对象地址,可以通过amp_mgr结构体内存地址检查一下是否正确,因为amp_mgr结构体偏移0x18处为l2cap_chan指针,如下图中红框所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


成功泄露l2cap_chan对象地址后,然后去填充amp_mgr结构体偏移0x10处的数据域。


复现测试


我们在ubuntu 5.4.0-26-generic系统下复现测试漏洞利用,执行过程如下:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


成功反弹root级shell,如下所示:


Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现


参考链接:

[1]https://google.github.io/security-research/pocs/linux/bleedingtooth/writeup

[2]https://github.com/google/security-research/security/advisories/GHSA-ccx2-w2r4-x649

[3]https://github.com/google/security-research/security/advisories/GHSA-7mh3-gq28-gfrq

[4]https://github.com/google/security-research/security/advisories/GHSA-h637-c88j-47wq




原文始发于微信公众号(Hack All):Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年11月13日15:45:51
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Linux内核蓝牙协议栈漏洞(BleedingTooth)利用分析与复现https://cn-sec.com/archives/1406808.html

发表评论

匿名网友 填写信息