【蓝牙】CVE-2018-9381 gatts_process_read_by_type_req未初始化栈变量导致信息泄露
补丁
https://android.googlesource.com/platform/system/bt/+/0519f6aa5345be0917ad52188479230148adf8bd
补丁初始化了两个变量,并且判断了传入的参数len,所以我们判断这里可能是len长度可以由攻击者控制,且后续直接使用了未初始化的栈变量
DO NOT MERGE Initialize local variable in gatts_process_read_by_type_req
Bug: 73125709
Test: manual
Change-Id: I8b3346f605e0820385ea5ed7401bbee664fd15aa
(cherry picked from commit 0e34139d7fa338df6c99aaba13eb839a3dbc2548)
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index 06c9c52..f9e8f53 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -788,7 +788,8 @@
void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
tBT_UUID uuid;
- uint16_t s_hdl, e_hdl, err_hdl = 0;
+ uint16_t s_hdl = 0, e_hdl = 0, err_hdl = 0;
+ if (len < 4) android_errorWriteLog(0x534e4554, "73125709");
tGATT_STATUS reason =
gatts_validate_packet_format(op_code, len, p_data, &uuid, s_hdl, e_hdl);通过源码来看整个过程,GATT的初始化函数
注意其中的gatt_le_data_ind,建立连接后,当L2CAP收到数据,就会调用这个函数
该函数的注释,这里在根据地址获取CCB
关键调用gatt_data_process(),注释里说,当我们是被连接的一端,那么我们就是ATT Server,所以,我们要处理来自Client的请求
switch判断op_code,进入GATT_REQ_READ_BY_TYPE,调用gatts_process_read_by_type_req()
结合补丁,我们可以猜测这里很有可能是未对栈变量做初始化,后面直接使用了,此时栈变量的值就是栈里原来的数据,我们跟入第一个函数gatts_validate_packet_format(),这里传入了s_hdl和e_hdl
注意参数,使用的是引用的方法,所以这里的变量修改就会影响上层传入的变量
跟入read_handles(),问题出现了,当len的长度小于4,就返回GATT_INVALID_PDU,此时没有对s_hdl和e_hdl进行赋值操作
返回上层函数,因为ret的值是GATT_INVALID_PDU,所以继续返回上层函数
回到了打补丁的函数,因为reason是GATT_INVALID_PDU,所以会调用gatt_send_error_rsp()返回错误信息给连接者(master)
这个函数返回一个错误的消息,从我们上面的分析来看,第四个参数uinit_t handle对应着传入的s_hdl
PoC如下,首先进行连接,send_trigger_req()里给p赋值为GATT_REQ_READ_BY_TYPE也就是0x08,赋值完后进行发送,此时发生错误,未初始化的栈变量被赋值到msg.error.handle,错误信息返回后被recv_and_leak()捕获,造成信息泄露,在recv_and_leak()里,因为cmd_code和reason都是uint8_t类型,所以需要跳过两字节才是handle,同时handle是uint16_t类型,所以使用STREAM_TO_UINT16读取
再来回顾下补丁,首先初始化栈变量s_hdl和e_hdl,避免后续继续出现同样的问题,同时判断传入的buffer长度,不能小于4
其它地方估计还会有不少这样的漏洞
Last updated