Linux内核蓝牙和谈栈缝隙(BleedingTooth)利用分析与复现
颁布功夫 2021-04-16缝隙概述
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和谈数据包的函数。代码实现如下所示:

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

凭据分歧的通路cid,进入分歧的子过程进行处置,进入l2cap_data_channel()函数。代码实现如下所示:

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

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

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

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

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

该if前提中,会挪用sk_filter()函数,此时chan->data为参数。而sk_filter()函数界说如下所示:

第一个参数类型为struct sock,而chan->data类型为struct amp_mgr,产生类型混合。
CVE-2020-12352
该缝隙是呈此刻a2mp和谈中,缝隙代码位于net/bluetooth/a2mp.c,多个函数使用未初始化的结构体,将数据返回到用户层,导致信息泄露,可泄露内核栈上的内存数据。缝隙道理较为单一,以a2mp_getinfo_req()函数为例,该函数是响应getinfo要求时挪用的,代码实现如下所示:

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

其只使用了rsp.id和rsp.status,其他的数据域未使用也未初始化,能够泄露16字节数据,而后挪用a2mp_send()函数将响应包发送到用户层,泄露内存数据。
CVE-2020-24490
该缝隙只能在bluetooth 5.0下触发,在bluetooth 5.0之前,HCI进行广播的最大数据长度为0x1F,0x20-0xFF保留。如下所示:

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

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

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

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

其中,discovery_state结构体界说如下所示:

last_adv_data数据大幼为HCI_MAX_AD_LENGTH,共31字节,当执行memcpy时产生溢出。
利用分析与复现
节造代码执行流程
前文分析到CVE-2020-12351类型混合是在sk_filter()函数中产生的,sk_filter()函数挪用sk_filter_trim_cap()函数,该函数代码实现如下:

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

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

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

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

一路挪用下来,最终会挪用到红框中的代码,简化一下挪用过程为:
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,偏移已经超出了领域。要解决这个问题,这里能够选取如下奇妙的堆喷布局:

结构体amp_mgr在kmalloc-128类型的slub中被分配,从第三个块起头,amp_mgr结构体偏移0x10处,能够被伪造成sk_filter,便能够满足sk对sk_filter域的解引用,并且可控。
布局载荷
通过堆喷占位节造代码执行流程后,接下来就是布局攻击载荷�D芄谎∪《雅�1024大幼的内存块去伪造l2cap_chan对象,由于结构体大幼为792,正好落在kmalloc-1024 slub块中,并且a2mp通路也属于l2cap通路中,开释a2mp通路时,l2cap通路也将被开释,操控起来较为矫捷,最终布局如下所示:

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

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

成功泄露l2cap_chan对象地址后,而后去填充amp_mgr结构体偏移0x10处的数据域。
复现测试
我们在ubuntu 5.4.0-26-generic系统下复现测试缝隙利用,执行过程如下:

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

参考链接:
[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
宝运莱官方网站积极防御尝试室(ADLab)
ADLab成立于1999年,是中国安全行业最早成立的攻防技术钻研尝试室之一,微软MAPP打算主题成员,“黑雀攻击”概想首推者。截止目前,ADLab已通过CVE累计颁布安全缝隙近1100个,通过 CNVD/CNNVD累计颁布安全缝隙1000余个,持续维持国际网络安全领域一流水准。尝试室钻研方向涵盖操作系统与利用系统安全钻延注智能终端安全钻延注物联网智能设备安全钻延注Web安全钻延注工控系统安全钻延注云安全钻研。钻研成就利用于产品主题技术钻延注国度沉点科技项目攻关、专业安全服务等。



京公网安备11010802024551号