實驗說明
在本實驗中,我們將研究如何分析OKLOK智能鎖安全性,并分析安卓APP,動態(tài)代碼調(diào)試和BLE分析控制,最終實現(xiàn)使用我們的代碼來遠(yuǎn)程控制智能門鎖。
我們將首先使用BLE適配器和Gatttool與智能鎖進(jìn)行交互,并探索設(shè)備上存在的服務(wù)和特征。然后,使用JEB對安卓APP進(jìn)行逆向,以了解服務(wù)和特征的含義。接著,我們將研究安卓APP和智能鎖之間的BLE流量。使用Android BLE日志記錄功能查看BLE流量,但也可以使用Ubertooth或任何其他BLE siffer。BLE流量和移動應(yīng)用程序的分析將使我們看到了通信已使用AES加密。
最后,我們將使用安卓APP插樁查找加密密鑰和其他值,我們將使用它們編寫自動腳本在無需任何身份驗證情況下,來接管智能鎖并解鎖。
所需資源
硬件
● 智能門鎖(OKLOK)
● BLE適配器
● 安卓手機(jī)(安裝OKLOK應(yīng)用程序)
● Ubertooth(可選)
軟件
● Wireshark
● Bettercap/Bleah
● Android device 1 Ubertooth-tools
● Jeb
● OKLOK.apk
● OKLOK_gadget.apk
OKLOK智能鎖介紹
OKLOK是具有藍(lán)牙低功耗(BLE)功能的智能掛鎖。除其他功能外,還可以使用適用于Android和ios的OKLOK應(yīng)用從手機(jī)遠(yuǎn)程操作掛鎖。在本實驗中,我們將分析Android應(yīng)用,了解如何將其與BLE利用方法結(jié)合使用以控制智能鎖。
該鎖支持使用注冊用戶的指紋進(jìn)行解鎖,但是在這里,我們僅關(guān)注BLE上的遠(yuǎn)程解鎖功能。
默認(rèn)情況下,鎖處于睡眠狀態(tài),即藍(lán)牙掃描器既看不到鎖,也不響應(yīng)BLE命令。為了使用它,必須通過觸摸鎖體上的指紋傳感器來激活它。激活后,鎖在閑置幾秒鐘后會自動返回到睡眠狀態(tài)。
OKLOK分析
初步分析
為了分析智能插頭,我們要做的第一件事是找到目標(biāo)智能鎖的地址。為此,我們將首先確保已連接BLE藍(lán)牙。運行hciconfig以查看智能鎖藍(lán)牙是否已成功連接到VM。
現(xiàn)在我們已經(jīng)將智能鎖藍(lán)牙連接到了VM,讓我們找出目標(biāo)Smart Lock的地址。
Hcitool檢測到我們的藍(lán)牙名稱為BlueFPL(藍(lán)色指紋鎖)的鎖,其藍(lán)牙地址為F8:33:31:DC:10:1F。我們還可以通過運行hcitool leinfo來查看有關(guān)BLE設(shè)備的更多信息,如下所示
hcitool工具集可以對藍(lán)牙進(jìn)行控制,工具集參數(shù)分為兩部分,一為正常的藍(lán)牙設(shè)備調(diào)試,二為低功耗即BLE設(shè)備, 工具參數(shù)如下:
現(xiàn)在使用Gatttol連接到設(shè)備,并探索設(shè)備上存在的服務(wù)和特征列表。使用hcitool是為了對設(shè)備的連接進(jìn)行管理,那么對BLE數(shù)據(jù)進(jìn)行精細(xì)化管理的話,就需要用到gatttool,使用gatttool對藍(lán)牙設(shè)備發(fā)送指令的操作上要比hcitool的cmd齊全很多,關(guān)于gatttool的使用分為兩種,直接使用參數(shù)對藍(lán)牙設(shè)備進(jìn)行控制,使用-I參數(shù)進(jìn)入gatttool的interactive模式對藍(lán)牙設(shè)備進(jìn)行控制。
1 sudo gatttool -i hci- interface -b device-address -I
現(xiàn)在,我們可以使用primary命令列出設(shè)備上存在的所有服務(wù)。
同樣,我們可以使用characteristics命令查看所有特性。
其中handle是特性的句柄,char properties是特性的屬性值,char value handle是特性值的句柄,uuid是特性的標(biāo)識;
我們還可以使用諸如Bleah(更改為Bettercap)之類的自動化工具來枚舉所有不同的特征,它們的屬性和存儲的值。為此,我們將使用以下命令。
1 $ bleah -b F8:33:31:DC:10:1F -e
Bleah掃描附近的BLE設(shè)備,以查找具有指定MAC地址的設(shè)備。找到后,它將連接到設(shè)備并枚舉所有服務(wù)和特征。
為了了解服務(wù)的目的及其特征,我們需要分析藍(lán)牙流量和Android應(yīng)用程序。
使用Android設(shè)備分析BLE流量
我們需要捕獲從應(yīng)用程序發(fā)送解鎖命令時生成的藍(lán)牙通訊。我們可以使用電腦上抓包嗅探技術(shù),也可以使用Android智能手機(jī)的內(nèi)置BLE日志記錄功能來實現(xiàn)。Android提供了“HCI監(jiān)聽日志”功能,可用于捕獲智能手機(jī)的藍(lán)牙流量。進(jìn)入APP,點擊“指紋設(shè)置”,然后點擊開鎖發(fā)送解鎖請求。
捕獲的藍(lán)牙流量將存儲在名為1.pcap的文件,我們可以將其傳輸?shù)絇C進(jìn)行進(jìn)一步分析。UUID fee7的服務(wù)具有兩個特性- UUID 36f5和36f6 handle 分別是 0x3和0x6,以及相應(yīng)的屬性為WRITE和NOTIFY。
在Wireshark中打開1.pcap文件并應(yīng)用過濾器(btatt.opcode ==“ Write Request” && btatt.handle == 3)
使用0x6 handle的過濾器,我們可以看到數(shù)據(jù)被加密了
解密流量
要繼續(xù)進(jìn)行,我們需要解密流量以了解遠(yuǎn)程解鎖過程的工作原理。我們使用JEB反編譯器分析Android應(yīng)用程序。
Package com.coolu.blelibrary.utils內(nèi)的BLEUtils類包含兩個方法Encrypt和Decrypt,從安全分析的角度來看,這兩個方法需要重點分析,這些方法將兩個字節(jié)數(shù)組作為參數(shù)。
第一個數(shù)組包含明文/密文,第二個數(shù)組包含密鑰。所使用的加密是ECB模式下的AES,無填充。
接下來是需要給手機(jī)安裝插樁處理過的應(yīng)用程序,手機(jī)連接藍(lán)牙鎖并執(zhí)行開鎖的操作,查看插樁的輸出結(jié)果。
AES密鑰是
210358453708121F305B503D3A5A5037。它的大小為16個字節(jié),這意味著密碼是AES-128。使用這個密鑰,我們可以解密我們在Wireshark中捕獲的數(shù)據(jù)包。我們將使用腳本oklok-decrypt.py來解密AES加密值。
在我們的加密數(shù)據(jù)包上運行腳本,我們得到以下結(jié)果。
我們來看看第一個解密的寫請求。它的開頭是0601,十進(jìn)制為1537。分析反編譯后的代碼,我們可以在com.coolu.blelibrary.mode包中找到一個類Order,其中包含了這些值的映射。1537代表GET_ TOKEN命令。
第二個命令是0201或十進(jìn)制的513。這是GET_ BATTERY命令.(InputDeviceCompat.SOURCE_ DPAD == 513).第三條命令是0501或1281(十進(jìn)制),這是OPEN_ LOCK命令。命令本身的名稱清楚地表明了它們的目的
在我們捕獲的BLE流量中,還有4個NOTIFY包,其中包含了對發(fā)送命令的響應(yīng)。
與WRITE數(shù)據(jù)包的情況相同,每個數(shù)據(jù)包的前兩個字節(jié)表示數(shù)據(jù)包類型,不同之處在于,其數(shù)值比相應(yīng)的WRITE數(shù)據(jù)包多一個。例如,GET_T0KEN的ID對于WRITE為0601,對于NOTIFY為0602。檢查包com. coolu . blelibrary中的CMDAPI類,我們可以發(fā)現(xiàn)這些消息的作用
因此,這四項響應(yīng)是
● CMD_TOKEN (0602)
● CMD_ GET_POWER (0202)
● CMD_ OPEN_ LOCK (0502)
● Unknown (050D): 在 CMDAPI 中沒有這樣的響應(yīng),但它很可能與 LOCK_ STATUS 有關(guān)。
解鎖
了解解鎖過程
通過研究流量,我們可以推斷出Android應(yīng)用通過寫入0x3句柄來發(fā)送命令,并且相應(yīng)的掛鎖通過在0x6句柄上發(fā)送通知來響應(yīng)。從Gatttool輸出(以及Bleah)中我們知道0x3句柄 對應(yīng)于UUID 000036f5- 0000-1000-8000- 00805f9b34fb,而0x6句柄對應(yīng)于000036f6-0000-1000 -800000805f9b34fb
我們可以使用包com.coolu.blelibrary中的BLEService類的反編譯代碼來驗證我們的發(fā)現(xiàn)。
TX_ UUID和RX_ UUID分別對應(yīng)于寫入和通知句柄。
下圖顯示了我們的目標(biāo)智能鎖的解鎖過程如何工作。
首先,應(yīng)用程序從設(shè)備獲取令牌,然后在后續(xù)命令中使用令牌。如上所述,所有請求和響應(yīng)均使用AES-128 ECB模式加密。
為了繞過應(yīng)用程序,實現(xiàn)自己打開鎖,我們需要遵循相同的邏輯流程。
為簡單起見,我們將省略獲取當(dāng)前電池電量的第二步,因為這對于我們的目的而言是多余的。
請求和響應(yīng)均為16字節(jié),前兩個字節(jié)指示命令類型。為了理解如何構(gòu)造命令本身,我們可以再次引用包com.coolu.blelibrary.mode中的反編譯類。
對于GET _TOKEN命令,我們有一個對應(yīng)的類GetTokenTxOrder。
從構(gòu)造函數(shù)調(diào)用的add方法在0601之后將兩個01字節(jié)追加到命令緩沖區(qū)。緩沖區(qū)的其余部分(12個字節(jié))在generateString方法中填充有隨機(jī)值。從包com.oklok.y.activity.lock中的LockInfoActivity類的反編譯代碼可以明顯看出,對通知句柄0x6上命令的響應(yīng)將包含四個字節(jié)的令牌。
相似地,對于OPEN LOCK命令,我們有一個對應(yīng)的類OpenLockTxOrder。
前兩個字節(jié)將包含命令類型0501,后跟06。接下來的六個字節(jié)包含某種密碼,在我們的測試中始終將其設(shè)置為0x30,而與鎖定密碼無關(guān)。在應(yīng)用程序上設(shè)置。接下來的四個字節(jié)包含在上一步中獲得的令牌。其余的三個字節(jié)填充有隨機(jī)值。
遠(yuǎn)程開鎖
利用所有這些信息,我們可以編寫腳本以連接到智能鎖并處理數(shù)據(jù)包,對其進(jìn)行加密并將其發(fā)送到設(shè)備以解鎖設(shè)備,而無需任何有關(guān)特定設(shè)備實例的身份驗證。
首先介紹一個python的第三方庫—bluepy
bluepy
bluepy 是github上一個很好的藍(lán)牙開源項目(https://github.com/IanHarvey/bluepy),其主要功能是用python實現(xiàn)linux上BLE的接口。
安裝過程參考官方說明。關(guān)于這個庫的使用官方也提供了詳細(xì)的文檔
(http://ianharvey.github.io/bluepy-doc/)
編寫代碼
首先是掃描附件的BLE設(shè)備,這里要使用bluepy 的Scanner類
通過官方文檔的描述,我們可以知道Scanner對象用于掃描正在廣播廣告數(shù)據(jù)的LE設(shè)備。在大多數(shù)情況下,這將提供一組可用于連接的設(shè)備。(但是請注意,藍(lán)牙LE設(shè)備可以接受連接而不廣播廣告數(shù)據(jù),或者可以廣播廣告數(shù)據(jù)但不接受連接)。
掃描結(jié)束后,通過getDevices()方法可以獲取掃描到的設(shè)備,尋找需要連接的藍(lán)牙鎖
1 for dev in s.getDevices():
2 if dev.getValueText(0x9) == 'BlueFPL':
3 print '[+] Found OKLOK'
4 connect(dev.addr)
5 break
找到后需要使用Peripheral類來連接藍(lán)牙鎖
通過官方文檔的描述,可以知道該類封裝了與Bluetooth LE外圍設(shè)備的連接??梢灾苯油ㄟ^指定其MAC地址來創(chuàng)建外圍對象。建立連接后,可以發(fā)現(xiàn)并讀取或?qū)懭朐撛O(shè)備提供的服務(wù)和特征。
接著使用getCharacteristics方法獲取設(shè)備的特性對象列表
1 p = Peripheral(addr)
2 write_char = p.getCharacteristics(uuid='000036f5-0000-1000-8000-00805f9b34fb')[0]
3 notify_char = p.getCharacteristics(uuid='000036f6-0000-1000-8000-00805f9b34fb'[0]
接著使用之前獲取的AES加密要發(fā)送的指令,發(fā)送開鎖的指令
1 if d.token != None:
2 cipher = AES.new(AESKEY.decode('hex'), AES.MODE_ECB)
3 # Send unlock command
4 pt = '050106303030303030'.decode('hex') + d.token + '\x00\x00\x00'
5 write_char.write(cipher.encrypt(pt))
6 print '[+] Sent unlock command'
即可完成開鎖。
原文來源:ChaMd5安全團(tuán)隊