Author: FengGouhtml
由於本身曾DIY過所謂的「智能硬件」,學習過程當中除了接觸各類芯片、傳感器、電路知識外,也拆了很多設備分析其設計思想學以至用。再後來又接觸瞭如:Wi-Fi、ZigBee、Bluetooth、NFC、IR、普通射頻甚至音頻等通訊技術,才發現空氣中那些形形色色的邊界,纔是整個物聯安全的關鍵。java
今天的內容是我在烏雲內部作的技術分享,也是我之前對低功耗藍牙技術的一些接觸,整理後決定對社區公佈。一來可讓社區對神祕的藍牙技術破冰;二來也是拋磚引玉,但願能看到更多有趣的案例;三來比起那些華麗麗的show,我更喜歡分享一些實際的內容。android
本次的研究目標是藍牙4.0中的低功耗技術(Bluetooth Low Energy)簡稱「BLE」,須要注意一些技術規範容易與經典藍牙搞混。git
正文開始前再看一段新聞報道吧,感覺下藍牙對當前以及將來在咱們生活中的影響力:github
2015年8月18~19日,藍牙技術聯盟(Bluetooth Special Interest Group,簡稱SIG)在上海舉辦2015藍牙亞洲大會。藍牙技術聯盟執行總監Mark Powell在會上指出,目前藍牙已經成爲全球使用量最大的無線技術。目前,藍設備的年出貨量在過去15年內增長了1000倍,已經達到了30億的水平,在將來的4~5年內還將增長到50億。安全
這裏本應該先講解藍牙與低功耗藍牙的基礎知識,但網上資料充足,因此各位仍是從文章最後的參考資料中學習吧。烏雲上也有白帽作了部分科普 Bluetooth Low Energy 嗅探 感謝他的分享。因此我只講基礎知識中的關鍵內容,而後多放些你們喜聞樂見的實戰案例。網絡
這個協議棧很是複雜,想基礎化了解BLE協議基礎的,就能夠參考最新藍牙4.2的官方文檔Bluetooth® Core Specification 4.2,我只簡單的提取我理解的關鍵部分。app
BLE設備的連接與加密、簽名協議的協商在這一層,好比BLE的兩種安全模式,首先是Security Mode 1,這個模式主要負責「加密」,它含有三個安全等級:ide
其次是Security Mode 2,這個模式主要負責「簽名」,它含有兩個安全等級:函數
PS:以上都是書本知識,具體能夠參照藍牙4.2官方文檔內對BLE安全的解說部分,注意不要跟藍牙混淆。
GATT負責兩個BLE設備間通訊的數據交互,是對功能數據最爲重要的部分,這篇文章的核心也在這裏。
如圖,GATT中的三個要素Profile、Service、Characteristic以及他們的層級關係,值得注意的是,Profile實際上是SIG藍牙技術聯盟給一些同範疇內的Service打包後的集合,好比電池、心率、血壓等,能夠參照官方 Profiles Overview 因此Profile對咱們的分析並沒有大用,不用放在心上。
Service和Characteristic是比較重要的,Service能夠理解爲PHP中的「類」,功能對象的集合。Characteristic能夠理解爲PHP的「函數」,是GATT中具體的功能對象,每一個Service均可以包含一個或多個Characteristic。
爲何說GATT很重要?由於理解了它,就已經可以分析或是「黑掉」一些BLE設備了。好比小米手環在國內某個硬件安全會議上被作過一個攻擊演示,使用Lightblue鏈接到手環後,只要用給其中一個Characteristic寫入1,就可讓手環震動起來,你們很驚訝但有不知因此然。我來用官方註冊的Characteristic角度解釋一下:
那個FEE7就是一個私有Service的UUID,裏面的0xFE**就是私有Characteristic的UUID,在往下面這個Immediate Alert 顯示出了名稱,表明其不是小米私有的Service,而是官方公開定義的Service,咱們點擊進入這個 Characteristic
看到了這個 Characteristic 的UUID 2A06,而後咱們去藍牙官網定義的列表 Characteristics 搜索 2A06,進入Characteristic的詳情頁面。
該 Characteristic 操做定義很是明確了:
值 | 含義 |
---|---|
無警告 | |
1 | 溫和的警告 |
2 | 強烈的警告 |
3~255 | 預留 |
因此你向UUID爲 0x2A06 的 Characteristic 寫入1的時候,小米手環會變會震動。其實你還能輸入2,這個快感比1更酸爽~哦呦、別、別停…… 這是一個簡單的GATT例子,不知各位是否明白,如今你能夠安裝個LightBlue連接你身邊的BLE設備,看看可否發現一些問題了呢?
小知識:GATT中的UUID有16bit和128bit兩種,官網看到那些都是16bit的(其實真正的通訊都是128bit的,官方UUID在第一段數據中能夠識別)。官方認證過的UUID是要花銀子的,但你能夠無償使用,保證軟硬件的相互理解。相反,私有UUID只有你本身的軟硬件纔可以理解,要弄明白功能就得技術性分析,也就是我後面要作的事情。
在遇到私有Service或Characteristic的時候,就要經過app逆向或嗅探藍牙通訊來分析了。說到藍牙嗅探,你們第一想到的確定是神器 Ubertooth One,精緻的硬件+配套的軟件變成了物聯網黑客強大的幫手,缺點你們有所體會——昂貴。在本身作了一些簡單的BLE設備研究後,瞭解到其實有更廉價的方案可供使用,這就是藍牙芯片廠所提供的BLE USB Dongle。
BLE USB Dongle,藍牙芯片廠商爲了方便開發者可以方便的調試藍牙產品通訊,就將這些藍牙芯片集成爲USB模塊,可進行方便的藍牙透傳測試。而你能夠燒入Sniffer固件,就能夠利用這個設備分析附近的藍牙通訊,而後將數據經過USB串口輸出到計算機上。
表明性的芯片有:
德州儀器(TI)的CC254x系列,配有官方的Sniffer程序,很是強大
北歐(Nordic)的NRF51822,串口輸出到計算機後,經過pipe方式使用Wireshark分析
我我的喜歡後者,由於我以爲這個數字對於我來講很吉利…吉利?…好吧,我就索性放棄Ubertooth One這款神器,給你們看看USB Dongle的其餘玩法:)另外注意,NRF51822是一塊單模(Bluetooth Smart)芯片,只支持BLE。具體參考官方文檔:nRF Sniffer User Guide v1.1
配置好環境以後就能夠對附近的設備通訊進行抓取了,我先來驗證一下書本知識。
這是BLE設備創建連接前主設備發給從設備的 CHANNEL_MAP_REQ 信息,用來告知BLE這40個信道哪些已經被佔用,哪些可使用。從中咱們能夠看到BLE頻率起始爲2402MHz,結束爲2480MHz,信道間距2MHz,有3個不可以使用的廣播信道3七、3八、39(頻段的起始、結尾與中心各設置一個廣播頻道,合理),這些都與書本知識吻合。
而後咱們選擇一個BLE設備的MAC地址進行Sniffer,注意必定要在設備鏈接前就指定mac監聽。監聽後隨便發起什麼經過藍牙信號的操做,咱們就抓取到了第一個BLE數據包
很激動有木有?如今抓取BLE通訊就猶如抓取網絡通訊同樣便捷了,連複雜的跳頻都先不用去考慮了撒。接下來再看最下面 Bluetooth Attribute Protocol 就是關鍵的 BLE 操做通訊內容,那個value是該產品的私有通訊協議。雖然如今看不懂意思,但並不是是加密所致,由於我前面有提到,我手裏的設備安全鏈路全是Security Mode 1 默認的Level 1這個級別…那私有協議如何分析?別急,後面的實戰部分我會介紹個人思路。
如今能夠分析BLE通訊了,接下來還要知道如何發送BLE信號,讓對方設備執行咱們指望的操做。其實要達成這個目標BLE USB Dongle或藍牙開發版就能夠實現,但爲了從此更多無線通訊測試的便捷性,我仍是準備打造一款軟硬結合的平臺。因此軟件我使用Linux官方的藍牙棧BlueZ(不少藍牙攻擊程序都是基於該藍牙棧),硬件我則選擇了CSR廠的CSR8510芯片藍牙適配器。平臺我用2代樹莓派搭建,將來會支持藍牙、RTL-SDR、ZigBee等常見無線通訊協議,比那些裝個kali2就叫「無線滲透」的設備可玩性多了些嘿嘿。
目前藍牙的設備塞在一塊兒就是醬紫了。
在這裏,咱們用Bluez自帶的hcitool掃描下沒開啓廣播的BLE設備,好比小米手環無處遁形。
在上一節BLE抓包後,咱們獲得的 Bluetooth Attribute Protocol 中的信息,就是發出BLE信號的關鍵部分:
操做:Read、Write仍是Notify(寫操做也不必定都是 write request 還有 write command,區別本身搜)
操做句柄,能夠簡單理解爲 Characteristic 的基址,真正的通訊地址
設備間傳輸的數據真身。有了這幾個信息,咱們就能夠調用BlueZ給設備發送修改後的信號了。
有了上面的理論基礎,要開始實戰了。我手頭上只有藍牙燈泡和小米手環,後來一個猥瑣的朋友借我個跳蛋但願幫忙分析…
首先這個燈泡我在分析前就敢確定他是存在問題的,由於燈泡的操做邏輯不會過於複雜,無非是一開一關、變色等等,因此我就拿他來作「Hello world」
1. 抓包燈泡的開關燈動做的value 2c2c2c3130302c2c2c2c2c2c2c2c2c2c2c2c(開) 2c2c2c302c2c2c2c2c2c2c2c2c2c2c2c2c2c(關)
看到差別了麼?
0x313030 = 100 0x30 = 0 從 4bytes 開始,就是該燈泡的亮度部分,100最亮,0沒有亮度,也就是關。
2. 抓包燈泡的換顏色動做 3235352c302c302c3130302c2c2c2c2c2c2c(紅色) 302c302c3235352c3130302c2c2c2c2c2c2c(藍色)
同上道理
0x3235352c302c30 = 255,0,0 0x302c302c323535 = 0,0,255 這就是RGB的顏色格式,很簡單直接告破:)最後看下 Handle 0x0012,來源如圖
最後,簡單的看下Bluez協議棧自帶的gatttool工具的使用方法
經過抓包分析得知操控燈泡顏色的handle是0x0012,我讀了下他的uuid爲fff1,私有的。用char-write-cmd命令直接寫入咱們分析好的協議,燈泡變色,而後再讀取之,數據確實成功寫入。
Demo:
這個產品感受邏輯也簡單,就是網絡遠程發送震動指令到手機,手機在經過BLE連接設備進行你懂、我懂、他也懂的事情,羞~
這個跳蛋有三種模式:預約義節奏的震動、隨着音樂翩翩起舞的震動還有一個體位交互震動,由於前兩個沒啥難度,基本抓到操做重放出來就OK了,最後這個模式比較卡哇伊,玩玩它咯。
與燈泡不一樣的是,進入體位模式後,Master會給Slave發送一個狀態開啓這個模式。因此你盲目的發送抓到的震動操做這個蛋是不震的,由於你要先讓她進入狀態。
給 Handle 0x0013 發送 0x0811060f01010232 後,它就進入狀態了。 而後 0x3e = 震動,0x7f = 生理暴擊(你狂按手機的時候就瘋狂的震動)
這個分析很簡單,由於都是些開關類的操做沒有太多實際的含義,因此無需解開數據,直接重放就能夠,我作了個發送SOS急救信號的demo。
Demo:
小米手環是明星產品,對他的分析也充滿了趣味與困難,由於從一開始我就遇到了一個認證機制,若是藍牙連接後不寫入一段特殊格式的數據,那你只能讀少許信息不能對手環進行操做。我經過抓包分析GATT中的write操做,過程省略2萬字,最終定位了一個向 Handle 0x0019 進行的write操做,該Characteristic返回了個Notify,而後手環就能夠隨意寫指令了(如私有協議中的震動、LED顏色變化、開啓實時步數監控等)。
不過認證怎麼能叫PWN?
不過認證怎麼能叫PWN?
不過認證怎麼能叫PWN?
重要的事情說三遍。小米手環的認證數據分析好了,結構以下
uid | 性別 | 身高&體重 | 暱稱 | 類型 | 簽名 |
---|---|---|---|---|---|
dcxxxx00 | 0100 | af3a00 | 66656e67676f7500 | 0000 | fe |
這個簽名是最重要的部分,前面的數據均可以僞造,只要簽名過了,手環就會容許你後續的寫指令,才能作到真正的PWN。那這個簽名是咋算出來的?請看番外篇。
劍走偏鋒,經過BlueZ獲得了小米手環一個完整的私有協議UUID,而後去Github搜索,但願找到官方的代碼(其實這部分經過逆向Android app相信就能獲得,不過說好的劍走偏鋒麼)
而後呢?duang~
彷佛是個第三方SDK,目前至少不用去逆向Android APP了開心,說實話這個我還真不擅長。經過這個SDK我找到了具體認證流程的代碼:
從這段代碼中分析,最終寫入Characteristic的內容,來自 userInfo.getBytes(device.getAddress()
public void setUserInfo(UserInfo userInfo) { BluetoothDevice device = this.io.getDevice(); this.io.writeCharacteristic(Profile.UUID_CHAR_USER_INFO, userInfo.getBytes(device.getAddress()), null); }
userInfo.getBytes 的設計在這裏,作了簡單註釋
public byte[] getBytes(String mBTAddress) { ... ByteBuffer bf = ByteBuffer.allocate(20); bf.put((byte) (uid & 0xff)); //uid bf.put((byte) (uid >> 8 & 0xff)); bf.put((byte) (uid >> 16 & 0xff)); bf.put((byte) (uid >> 24 & 0xff)); bf.put(this.gender); //性別 bf.put(this.age); //年齡 bf.put(this.height); //身高 bf.put(this.weight); //體重 bf.put(this.type); //類型 if(aliasBytes.length<=10) { bf.put(aliasBytes); bf.put(new byte[10-aliasBytes.length]); }else{ bf.put(aliasBytes,0,10); } byte[] crcSequence = new byte[19]; //取出用戶信息的前19個字節 for (int u = 0; u < crcSequence.length; u++) crcSequence[u] = bf.array()[u]; byte crcb = (byte) ((getCRC8(crcSequence) ^ Integer.parseInt(mBTAddress.substring(mBTAddress.length()-2), 16)) & 0xff); bf.put(crcb); //將簽名跟前面的用戶信息拼接 return bf.array(); //最終寫入Characteristic的內容 }
uid | 性別 | 身高&體重 | 暱稱第1byte湊齊19byte | MAC最後2byte |
---|---|---|---|---|
dcxxxx00 | 0100 | af3a00 | 6 | FC |
這個數據與MAC地址最後兩位FC進行異或爲16byte數據,在轉爲2byte的hex簽名結果。用戶信息與手機端無需一致,只要簽名正確便可。這裏感謝 @瘦蛟舞 的幫忙,用java程序幫我作了個接口,這樣我就能根據MAC地址任意生成有效的認證數據了。
完整代碼也不放出了,畢竟能夠秒殺手環認證:)
解決了認證的難題,接下來就是壓軸大戲,如何對用戶以及產品口碑形成真正的影響。震動?改步數?LED跑馬燈?都不是,我選擇在茫茫人羣中,給你寫入惡意的鬧鈴,名曰 午夜兇「鈴」。試想下,揹着我那臺無線Hack設備,每天在早高峯蹭北京城鐵13號線,自動搜索身邊小米手環,而後連接過認證寫入鬧鈴,大家猜一個月後我能「感染」多少手環?我相信不用多久,小米手環論壇就會有用戶鬧翻天了…光說不練耍流氓,實現它。選擇設備後抓包,客戶端設置幾回鬧鈴,只要一次我就解開私有協議格式了:
同樣簡單,數據格式我畫出來。第一位說明當前的操做是鬧鈴,第二位是鬧鈴的序號,第三位鬧鈴的開關,第四位開始就是鬧鈴時間,倒數第二位是智能喚醒(就是在你淺睡眠的時候把你叫起,可是我偏不,就是要在你深度睡眠時喚醒你,木哈哈),最後一位就是鬧鈴的循環日期,0x7F就是天天。
寫好測試程序,搜索並連接手環經過那個「認證」獲取操做權限,再用手環LED玩個跑馬燈,最後華麗麗的寫入鬧鈴釋放連接。結果手機客戶端連上去發現鬧!鈴!沒!開!啓!仍是默認的關閉狀態,不放棄繼續分析,我是越挫越勇的……
經過後面的分析發現,這個地方是小米手環客戶端(至少iOS客戶端)的BUG,手環開發組GG認爲手環的數據只有經過客戶端進行開啓修改,因此非客戶端寫入的數據不會自動同步!也就形成了惡意鬧鈴雖然寫入成功,但客戶端看不到,認爲鬧鈴沒有變化不去同步最新的狀態,但這反讓攻擊變的更加隱蔽了,嘖嘖。
看演示吧,POC代碼不放,由於細心動手的人能夠經過個人分析解決一切問題,也避免真的有人直接利用代碼對小米用戶進行攻擊(因測試成功後忘記取消以前設置的午夜兇「鈴」,因此我成了第一個受害者,大半夜太酸爽了)。
Demo:
內容沒有涉及任何經典/低功耗藍牙的協議加解密、簽名、配對兒認證等安全機制,畢竟是初探,不搞那麼複雜高大上變成學術文章。因此我先分享一些接地氣兒的產品和攻擊場景,但願可以創建夥伴們對物聯網安全的興趣。
BLE在藍牙中都是很小的一部分,在物聯網汪洋大海中更是一葉扁舟,學海無涯但願路上有你。
PS:以上的內容我我的認爲並非漏洞,畢竟還得10米的攻擊範圍內,因此直接當作技術分享吧。