BlueBorne 之 CVE-2017-0785 原理分析
字数 2921 2025-08-22 12:22:48

BlueBorne漏洞集之CVE-2017-0785深度分析

1. 漏洞概述

CVE-2017-0785是BlueBorne漏洞集中的一个重要漏洞,影响Android系统的BlueDroid和Fluoride蓝牙协议栈实现。该漏洞源于SDP(Service Discovery Protocol)服务器对continuation state处理不当,导致内存信息泄露,可被攻击者用于绕过ASLR(地址空间布局随机化)保护机制。

2. 背景知识

2.1 SDP协议简介

SDP(Service Discovery Protocol)是经典蓝牙中的高层协议,采用C/S架构,用于客户端发现服务器提供的服务。关键特点包括:

  • 客户端必须等待服务器响应当前请求PDU后才能发送下一个请求PDU
  • 请求PDU携带限制响应PDU大小的字段,如MaximumAttributeByteCount
  • 响应PDU携带相应字段表示返回数据长度,如AttributeListsByteCount

2.2 Continuation State机制

当服务器发现请求数据无法在一个响应PDU中完整返回时,会使用continuation state机制分段传输数据:

  1. 分段大小不一定用完MaximumAttributeByteCount定义的最大值
  2. 传输分段数据的响应PDU必须携带ContinuationState字段
  3. ContinuationState由两部分组成:
    • InfoLength:表示continuation information的长度(最大0x10)
    • Continuation Information:用于解决分段传输问题的神奇字段

2.3 L2CAP导致的数据分段

实际场景中,数据分段更多由L2CAP(Logical Link Control and Adaptation Protocol)限制引起:

  • L2CAP承载SDP PDU传输
  • 连接建立时设备交换各自支持的MTU(Maximum Transmission Unit)
  • 当SDP响应数据超过远端设备L2CAP设置的MTU时,启用continuation state分段传输

2.4 Android对Continuation Information的定义

Android对蓝牙核心规范未明确定义的continuation information字段做了具体实现:

// platform/system/bt/stack/sdp/sdpint.h#200
typedef struct {
  uint16_t len;         /* length of the continuation info */
  uint8_t* data;        /* the continuation data */
  uint16_t offset;      /* the offset within the data */
} tCONNECTION_STATE;

cont_offset的具体含义有两种情况:

  1. 使用SDP_SERVICE_SEARCH_REQ/RSP PDU时:

    • 表示下一个分段中起始数据项相对不分段完整数据项的偏移
    • 例如已返回10个service record handle,cont_offset为10
  2. 使用SDP_SERVICE_ATTR_REQ/RSP或SDP_SERVICE_SEARCH_ATTR_REQ/RSP时:

    • 表示下一个分段的数据相对不分段完整数据的偏移(字节为单位)

3. 漏洞详细分析

3.1 漏洞触发流程

  1. SDP服务器处理请求PDU时进入sdp_server_handle_client_req()

  2. 当请求PDU为SDP_SERVICE_SEARCH_REQ时,进入process_service_search()

  3. 提取三个关键参数:

    • ServiceSearchPattern → uid_seq
    • MaximumServiceRecordCount → max_replies
    • ContinuationState → cont_offset
  4. 若使能continuation state,会检查cont_offset与先前传给客户端值是否相等

  5. 根据uid_seq和max_replies找到匹配的service record handle,存储在rsp_handles数组

  6. max_replies限制handle总数num_rsp_handles

3.2 漏洞根本原因

关键问题在于num_rsp_handles的计算方式:

  1. 对于每个请求,num_rsp_handles都会被重新计算
  2. 使用continuation state时,所有上下文相同请求应使用相同uid_seq和max_replies
  3. 但AOSP未检查每次计算的num_rsp_handles是否相同

攻击者可利用此缺陷:

  1. 先发送普通SDP_SERVICE_SEARCH_REQ PDU,正常触发continuation state
  2. 然后发送MaximumServiceRecordCount为1的continuation state PDU
  3. 导致num_rsp_handles值被篡改为1

3.3 内存泄露过程

  1. 当num_rsp_handles=1且使能continuation state时:

    • 计算剩余需传输handle数量:rem_handles = num_rsp_handles - cont_offset
    • 由于num_rsp_handles被篡改为1,rem_handles(uint16_t)发生下溢
  2. 下溢的rem_handles总是大于cur_handles(当前PDU能携带的handle数量)

    • 导致continuation state恒使能
  3. 服务器尝试读取rsp_handles[cont_offset]到rsp_handles[cont_offset + cur_handles]

    • cont_offset持续增大
    • 最终导致数组越界读,泄露内存信息

4. 漏洞利用技术细节

4.1 关键数据结构

typedef struct {
  uint16_t len;         /* length of the continuation info */
  uint8_t* data;        /* the continuation data */
  uint16_t offset;      /* the offset within the data */
} tCONNECTION_STATE;

4.2 漏洞代码片段

关键漏洞代码位于process_service_search()函数:

// platform/system/bt/stack/sdp/sdp_server.cc#207
num_rsp_handles = get_num_matching_records(uid_seq);
if (num_rsp_handles > max_replies) num_rsp_handles = max_replies;

// platform/system/bt/stack/sdp/sdp_server.cc#227
rem_handles = num_rsp_handles - cont_offset;  // Underflow here when exploited

// platform/system/bt/stack/sdp/sdp_server.cc#236
if (rem_handles <= cur_handles) {
  cont_info_needed = false;
} else {
  cont_info_needed = true;
}

// platform/system/bt/stack/sdp/sdp_server.cc#269
for (xx = cont_offset; xx < cont_offset + cur_handles; xx++) {
  /* This will eventually read out of bounds */
  UINT16_TO_BE_STREAM(p, rsp_handles[xx]);
}

4.3 攻击步骤

  1. 建立正常L2CAP连接,配置小MTU增加触发continuation state概率
  2. 发送普通SDP_SERVICE_SEARCH_REQ PDU,建立合法continuation state上下文
  3. 发送特制PDU,将MaximumServiceRecordCount设为1
  4. 服务器计算num_rsp_handles=1,导致后续rem_handles下溢
  5. 利用恒使能的continuation state逐步读取越界内存
  6. 收集泄露的内存信息用于绕过ASLR

5. 防御建议

  1. 检查continuation state上下文中的num_rsp_handles一致性
  2. 对rem_handles计算进行边界检查,防止整数下溢
  3. 验证cont_offset不超过rsp_handles数组边界
  4. 更新到已修复漏洞的蓝牙协议栈版本

6. 参考资源

  1. Bluetooth Core Specification Version 5.2 | Vol 3, Part B
  2. BlueBorne Technical White Paper
  3. Android AOSP源码(android-8.0.0_r1标签)
  4. CVE-2017-0785官方描述
BlueBorne漏洞集之CVE-2017-0785深度分析 1. 漏洞概述 CVE-2017-0785是BlueBorne漏洞集中的一个重要漏洞,影响Android系统的BlueDroid和Fluoride蓝牙协议栈实现。该漏洞源于SDP(Service Discovery Protocol)服务器对continuation state处理不当,导致内存信息泄露,可被攻击者用于绕过ASLR(地址空间布局随机化)保护机制。 2. 背景知识 2.1 SDP协议简介 SDP(Service Discovery Protocol)是经典蓝牙中的高层协议,采用C/S架构,用于客户端发现服务器提供的服务。关键特点包括: 客户端必须等待服务器响应当前请求PDU后才能发送下一个请求PDU 请求PDU携带限制响应PDU大小的字段,如MaximumAttributeByteCount 响应PDU携带相应字段表示返回数据长度,如AttributeListsByteCount 2.2 Continuation State机制 当服务器发现请求数据无法在一个响应PDU中完整返回时,会使用continuation state机制分段传输数据: 分段大小不一定用完MaximumAttributeByteCount定义的最大值 传输分段数据的响应PDU必须携带ContinuationState字段 ContinuationState由两部分组成: InfoLength:表示continuation information的长度(最大0x10) Continuation Information:用于解决分段传输问题的神奇字段 2.3 L2CAP导致的数据分段 实际场景中,数据分段更多由L2CAP(Logical Link Control and Adaptation Protocol)限制引起: L2CAP承载SDP PDU传输 连接建立时设备交换各自支持的MTU(Maximum Transmission Unit) 当SDP响应数据超过远端设备L2CAP设置的MTU时,启用continuation state分段传输 2.4 Android对Continuation Information的定义 Android对蓝牙核心规范未明确定义的continuation information字段做了具体实现: cont_ offset的具体含义有两种情况: 使用SDP_ SERVICE_ SEARCH_ REQ/RSP PDU时: 表示下一个分段中起始数据项相对不分段完整数据项的偏移 例如已返回10个service record handle,cont_ offset为10 使用SDP_ SERVICE_ ATTR_ REQ/RSP或SDP_ SERVICE_ SEARCH_ ATTR_ REQ/RSP时: 表示下一个分段的数据相对不分段完整数据的偏移(字节为单位) 3. 漏洞详细分析 3.1 漏洞触发流程 SDP服务器处理请求PDU时进入 sdp_server_handle_client_req() 当请求PDU为SDP_ SERVICE_ SEARCH_ REQ时,进入 process_service_search() 提取三个关键参数: ServiceSearchPattern → uid_ seq MaximumServiceRecordCount → max_ replies ContinuationState → cont_ offset 若使能continuation state,会检查cont_ offset与先前传给客户端值是否相等 根据uid_ seq和max_ replies找到匹配的service record handle,存储在rsp_ handles数组 max_ replies限制handle总数num_ rsp_ handles 3.2 漏洞根本原因 关键问题在于num_ rsp_ handles的计算方式: 对于每个请求,num_ rsp_ handles都会被重新计算 使用continuation state时,所有上下文相同请求应使用相同uid_ seq和max_ replies 但AOSP未检查每次计算的num_ rsp_ handles是否相同 攻击者可利用此缺陷: 先发送普通SDP_ SERVICE_ SEARCH_ REQ PDU,正常触发continuation state 然后发送MaximumServiceRecordCount为1的continuation state PDU 导致num_ rsp_ handles值被篡改为1 3.3 内存泄露过程 当num_ rsp_ handles=1且使能continuation state时: 计算剩余需传输handle数量:rem_ handles = num_ rsp_ handles - cont_ offset 由于num_ rsp_ handles被篡改为1,rem_ handles(uint16_ t)发生下溢 下溢的rem_ handles总是大于cur_ handles(当前PDU能携带的handle数量) 导致continuation state恒使能 服务器尝试读取rsp_ handles[ cont_ offset]到rsp_ handles[ cont_ offset + cur_ handles ] cont_ offset持续增大 最终导致数组越界读,泄露内存信息 4. 漏洞利用技术细节 4.1 关键数据结构 4.2 漏洞代码片段 关键漏洞代码位于 process_service_search() 函数: 4.3 攻击步骤 建立正常L2CAP连接,配置小MTU增加触发continuation state概率 发送普通SDP_ SERVICE_ SEARCH_ REQ PDU,建立合法continuation state上下文 发送特制PDU,将MaximumServiceRecordCount设为1 服务器计算num_ rsp_ handles=1,导致后续rem_ handles下溢 利用恒使能的continuation state逐步读取越界内存 收集泄露的内存信息用于绕过ASLR 5. 防御建议 检查continuation state上下文中的num_ rsp_ handles一致性 对rem_ handles计算进行边界检查,防止整数下溢 验证cont_ offset不超过rsp_ handles数组边界 更新到已修复漏洞的蓝牙协议栈版本 6. 参考资源 Bluetooth Core Specification Version 5.2 | Vol 3, Part B BlueBorne Technical White Paper Android AOSP源码(android-8.0.0_ r1标签) CVE-2017-0785官方描述