|快速理解Android中的三个蓝牙漏洞( 四 )

'') else: if os.getuid(): print ''Error: This script must be run as root.'' else: main(*sys.argv[1:])漏洞3:Bluetooth SMP smp_sm_event() OOB Array Indexing
Bluetooth SMP smp_sm_event() OOB阵列索引
简要
蓝牙范围内的远程攻击者可以使用Android 蓝牙堆栈中的漏洞 , 通过以意外传输方式将包含SMP_OPCODE_PAIRING_REQ命令的SMP数据包发送到目标设备 , 从而使com.android.bluetooth守护程序访问其边界之外的数组 。
前置介绍
安全管理协议SMP
SMP(The Security Manager Protocol )
连接建立之后 , 双方通过某些方式协商共同的密钥 , 然后将后续要传输的数据用这个密钥通过加密算法进行加密 , 然后发送 。 接收方 , 接收到这些数据后 , 必须使用正确的密钥来解密 , 才能得到正确的数据了 。 接着 , 建立密钥 , 即完成双方密钥协商 , 就密钥一事达成共同一致的过程 。
过程如图所示:
|快速理解Android中的三个蓝牙漏洞
本文插图

为运行在低功耗蓝牙协议栈上的应用程序提供诸如身份验证 , 设备授权和数据隐私等服务的权限 。
漏洞详情
数组索引只接受0x0和0x1 , 而作为索引的变量还能设置为0xff , 导致后续引用可能导致分段错误
SMP协议通过预定义的L2CAP_SMP_CID(0x06)通道 , 位于L2CAP之上 。
传入的SMP数据包由smp_data_received()函数[ platform / system / bt / stack / smp / smp_l2c.cc ]处理 。 如果 通过包含SMP_OPCODE_PAIRING_REQ(0x01)命令的L2CAP_SMP_CID固定通道 接收到输入SMP数据包 , 则将到达以下代码:
static void smp_data_received(uint16_t channel, const RawAddress& bd_addr, BT_HDR* p_buf) { [...] /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) { if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) && !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { p_cb->role = L2CA_GetBleConnRole(bd_addr); [...]如上面的代码所示 , 最后一行中p_cb-> role设置为L2CA_GetBleConnRole(bd_addr)返回的值 。 p_cb-> role应该保存以下值之一[ platform / system / bt / stack / include / hcidefs.h ] , 也就是 p_cb->role的值可以是0x00、0x01、0xff
/* HCI role defenitions */ #define HCI_ROLE_MASTER 0x00 #define HCI_ROLE_SLAVE 0x01 #define HCI_ROLE_UNKNOWN 0xff如果我们查看L2CA_GetBleConnRole()函数的代码[ platform / system / bt / stack / l2cap / l2c_ble.cc ] , 我们可以看到它调用了l2cu_find_lcb_by_bd_addr()为了查找活跃的链接控制块(an active Link Control Block)(LCB)结构匹配远程BDADDR并且使用低能耗传输(BT_TRANSPORT_LE);如果找不到它 , 则返回HCI_ROLE_UNKNOWN(0xff) 。 当我们通过BR/EDR(基本速率/增强数据速率 , 也称为“经典”蓝牙)传输发送包含SMP_OPCODE_PAIRING_REQ命令的SMP数据包时 , 这种情况会发生 , 因为它只适用于低能量(LE)传输:
uint8_t L2CA_GetBleConnRole(const RawAddress& bd_addr) { uint8_t role = HCI_ROLE_UNKNOWN; tL2C_LCB* p_lcb; p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); if (p_lcb != NULL) role = p_lcb->link_role; return role; }因此 , 回到smp_data_received()函数 , 将p_cb-> role设置为HCI_ROLE_UNKNOWN(0xff)之后 , 它调用smp_sm_event() [ platform / system / bt / stack / smp / smp_main.cc ] , 我们到达以下代码:


推荐阅读