Android蓝牙子系统“BlueFrag”缝隙分析(CVE-2020-0022)
颁布功夫 2020-02-13一、缝隙布景
2020年2月,,,,,Android安全布告中披露并建复了一个严沉缝隙,,,,,缝隙编号为CVE-2020-0022,,,,,又称BlueFrag,,,,,可影响Android蓝牙子系统。。。。。该缝隙是一个远程代码执行缝隙,,,,,呈此刻Bluedroid蓝牙和谈栈的HCI层,,,,,当无线模浚�???榇τ诨疃刺�,,,,,攻击者能够利用蓝牙守护法式提升权限进而在设备上执行代码。。。。。该缝隙影响Android Oreo(8.0和8.1)、Pie(9),,,,,但无法在Android 10上进行利用,,,,,仅能触发DoS攻击。。。。。
二、和谈简介
2.1 HCI
HCI 层位于蓝牙和谈栈高层和谈和低层和谈之间,,,,,提供了对基带节造器和链路治理器的号令以及接见蓝牙硬件的统一接口步骤,,,,,其接口合用于BR/EDR节造器、BR/EDR/LE节造器、LE节造器、AMP节造器,,,,,与底层的结构关系如下图:
主机系统上的HCI驱动法式和节造器中的HCI层之间会存在中央层,,,,, 这些中央层即是主机节造器传输层,,,,,这些传输层是通明的,,,,,只需实现传输数据的工作,,,,,不用明显数据的具体体式。。。。。两个蓝牙设备点对点HCI层的交互过程如下图所示:
2.1.1 HCI包体式
HCI通过包的方式来传送数据、号令和事务的,,,,,所有在主机和主机节造器之间的通讯都以包的大局进行。。。。。蕴含每个号令的返回参数都通过特定的事务包来传输。。。。。HCI罕见据、号令和事务三种类型的包。。。。。号令包COMMAND(0x01)只能从主机发往主机节造器,,,,,其中数据包是双向的,,,,,分为两类:ACL(0x02)、SCO(0x03),,,,,而事务包EVENT(0x04)始终是主机节造器发向主机的。。。。。主机发出的大无数号令包城市触发主机节造器产生相应的事务包作为响应,,,,,在传输过程中会有一个句柄,,,,,用于鉴别主机之间的逻辑通路和节造器,,,,,共有三种类型的句柄:衔接句柄、逻辑链路句柄和物理链路句柄。。。。。
凭据必要,,,,,这里只介绍ACL数据包体式,,,,,ACL 数据用于主机和节造器之间的非同步数据互换,,,,,如播放音乐数据的数据包,,,,,体式如下图:
每个字段的注明如下所示:
|
字段 |
注明 |
|
Handle |
Connection_Handle用于在主节造器上传输数据包或段。。。。。 |
|
PB Flag |
包天堑和适应领域。。。。。 |
|
BC Flag |
广播标志。。。。。 |
|
Data Total Length |
以八位位组为单元的数据长度,,,,,蕴含高层和谈data。。。。。 |
其中,,,,,PB Flag的描述如下:
设置为 00'b 的时辰,,,,,代表 Host -> Contoller 的 L2CAP 的首包。。。。。设置为 01’b 的时辰,,,,,代表 Host -> Contoller 或者 Contoller -> Host 的 L2CAP 的续包(中央的)。。。。。设置为 10'b 的时辰,,,,,代表 Contoller -> Host 的 L2CAP 的首包。。。。。
2.1.2 分段(Fragmentation)和沉组(Reassembly )
分段是将PDU分化成较幼的部门,,,,,以便从L2CAP传递到较低层。。。。。沉组是凭据从基层传递来的片段沉组PDU的过程。。。。。分段和沉组能够利用于任何L2CAP PDU。。。。。
2.2 L2CAP数据包体式
L2CAP是基于分组的,,,,,但也遵循信路传输的通讯模型。。。。。L2CAP支持的信路有两种:面向衔接的信路和面向无衔接的信路。。。。。在面向衔接的信路中,,,,,L2CAP数据包的体式如下图所示。。。。。
数据包中每个字段的注明如下所示:
|
字段 |
注明 |
|
Length |
2字节,,,,,暗示信息有效负载的大幼,,,,,不蕴含长度L2CAP头。。。。。 |
|
Channel ID(CID) |
2字节,,,,,用于标识主张信路的终端。。。。。通路ID的领域与在发送数据包的设备有关。。。。。 |
|
Information(Payload) |
信息负载。。。。。长度为0到65535字节。。。。。 |
三、缝隙道理分析
CVE-2020-0022缝隙位于HCI层,,,,,缝隙补丁代码位于hci/src/packet_fragmenter.cc(以8.1.0_r33为例)中的reassemble_and_dispatch()函数中,,,,,该函数是用于数据包吩飕的沉组。。。。。对于过长的ACL数据包必要进行包的沉组,,,,,重要是凭据ACL包中的PB Flag标志位进行沉组,,,,,若是当前是肇始部门并且是不齐全的,,,,,则天生一个部门包(partial_packet)放到map里,,,,,等下次收到它的后续部门进行组装,,,,,组装结束后就分发出去。。。。。具体分析reassemble_and_dispatch()函数如下:
首先,,,,,处置第一个packet,,,,,代码127行到129行,,,,,别离读取handle、acl_length和l2cap_length。。。。。handle为本次链路的Connection_Handle。。。。。凭据前文数据包体式的介绍,,,,,acl_length为Data Total Length,,,,,该data数据域中存放着L2CAP数据包吩飕(也可能是一个齐全的L2CAP数据包)。。。。。而后,,,,,直接读取data中L2CAP Length,,,,,该l2cap_length是一个齐全的L2CAP数据包中payload的长度。。。。。行131,,,,,校验packet包长度是否正常。。。。。行133,,,,,通过handle获取boundary_flag,,,,,即是PB Flag。。。。。
行136,,,,,判断boundary_flag是否为2,,,,,二进造暗示为10’b,,,,,即判断当前packet是否为 Contoller -> Host 的 L2CAP 的首包,,,,,若是是,,,,,进入if语句。。。。。行137到行147,,,,,判断当前packet是否已经被处置,,,,,保障本次处置的packet都是最新的。。。。。行149到行154,,,,,判断L2CAP数据包长度是否正常,,,,,不正常直接报错返回。。。。。
接下来,,,,,行156到行157,,,,,推算full_length,,,,,其中蕴含一个齐全的L2CAP数据包中的payload的长度,,,,,一个L2CAP头部长度和一个HCI头部长度。。。。。行161到行168,,,,,判断full_length是否超过BT_DEFAULT_BUFFER_SIZE,,,,,若是超过直接报错返回。。。。。行170到行178,,,,,判断当前头包packet是否还有续包,,,,,若是没有续包直接挪用callbacks->reassembled处置当前packet并返回。。。。。
若是当前头包packet后面还有续包,,,,,那就起头沉新分配一块新的内存用于packet中数据包沉组。。。。。行180到184,,,,,分配并设置partial_packet,,,,,将partial_packet->len设置为full_length,,,,,将partial_packet->offset设置为packet->len即当前头包packet->data的长度。。。。。行186,,,,,挪用memcpy,,,,,将头包packet中HCI数据包整体拷贝到partial_packet中。。。。。行189到行191,,,,,先找到HCI数据包头部,,,,,并跳过handle,,,,,更新acl_length为一个齐全的L2CAP数据包长度。。。。。行193,,,,,将partial_packet存放到容器中。。。。。行196,,,,,开释当前头包packet,,,,,暗示已经处置完第一个packet,,,,,不再必要它了。。。。。行197,,,,,else语句起头处置后续packet,,,,,即boundary_flag不蹬宗2的packet。。。。。
行198到行205,,,,,首先通过handle判断当前后续packet是否属于本次链路的,,,,,若是不属于,,,,,直接返回。。。。。行206,,,,,获取前一轮天生的partial_packet。。。。。行208,,,,,将当前后续packet->offset赋值为HCI_ACL_PREAMBLE_SIZE即4字节,,,,,此时packet->offset指向HCI包中的data域,,,,,里面存放着L2CAP数据包吩飕。。。。。行209和行210,,,,,推算projected_offset,,,,,projected_offset为partial_packet->offset与本次L2CAP数据包吩飕的长度之和。。。。。
行211和行219,,,,,判断projected_offset是否大于partial_packet->len,即判断projected_offset是否大于full_length。。。。。若是大于,,,,,则批改packet->len为partial_packet->len减去partial_packet->offset,,,,,即packet->len为partial_packet渣滓空间的长度。。。。。而后,,,,,将projected_offset设置为partial_packet->len。。。。。具体数据包沉组如下图所示:
建改好现实要拷贝的长度后,,,,,行221,,,,,挪用memcpy进行拷贝,,,,,缝隙点到了,第一个参数为partial_packet->data + partial_packet->offset,主张地址是正确的,,,,,第二个参数为packet->data + packet->offset,,,,,源地址也是正确的,,,,,第三个参数是要拷贝的长度len为packet->len - packet->offset,,,,,这个值是有问题的,,,,,分两种情况。。。。。第一种情况是projected_offset幼于partial_packet->len,,,,,packet->len - packet->offset为L2CAP数据包片段总长度,,,,,并且是个正数。。。。。第二种是行211的情况,,,,,packet->len已经被建自新,,,,,不必要再一次packet->len - packet->offset的操作,,,,,若是partial_packet渣滓空间长度幼于4字节,,,,,那packet->len - packet->offset 是幼于零的,,,,,是一个负数。。。。。由于memcpy()函数第三个参数类型是一个无符号整型类型,,,,,因而整数溢出导致堆溢出。。。。。缝隙补丁如下:
能够看到,,,,,补丁代码中将packet->len加上了一个packet->offset,,,,,用于后面抵消减packet->offset的操作。。。。。
四、影响版本
Android Oreo(8.0和8.1)
Android Pie(9)
Android 10
五、安全建议
尽快更新最新的Android安全补丁
仅在绝对必要时启用蓝牙
维持蓝牙设备不成发现
参考信息:
1.https://insinuator.net/2020/02/critical-bluetooth-vulnerability-in-android-cve-2020-0022/
2.https://akhozo.blogspot.com/2020/02/critical-android-bluetooth-flaw-cve.html?spref=tw
3.https://android.googlesource.com/platform/system/bt/+/3cb7149d8fed2d7d77ceaa95bf845224c4db3baf%5E%21/#F0
4.https://source.android.com/security/bulletin/2020-02-01.html
5.http://androidxref.com/8.1.0_r33/xref/system/bt/hci/src/packet_fragmenter.cc
6.Bluetooth_Core_v4.2蓝牙官方文档


京公网安备11010802024551号