https://www.jianshu.com/p/028b10bc3dd1
智能設備的聯動通常采用IFTTT的方式,但這種方式受限於官方軟件提供的功能。想要自主地靈活控制,需要有官方SDK,或知道協議細節。本文通過捕獲、分析Broadlink SP設備(含SP2和SP mini)的協議數據,達到重放(replay)控制的效果。在這個過程中,對其安全性也有了更深入的認識。
有前人做過類似的工作,但抓包過程較為繁瑣。本文的方法比較便捷,可以很容易地進行本地和遠程的分析。這個方法也可供研究其它智能設備時借鑒。
在路由器上用tcpdump抓包,基本行為研究
家里的路由器是刷了OpenWRT的,所以可以直接嘗試在路由器上用tcpdump抓包。
實驗1:不打開任何App時,觀察插座上的活動。
命令:tcpdump -i ra0 udp and host sp3 -U -s0 -w /tmp/tmp.pcap -c 30 -vvv
(sp3是我的第3個SP類型的設備,並不是指型號;上面的命令是抓到30個UDP包就停止)
在Wireshark中打開抓獲的pcap文件:

可以看到:大約每25秒,插座會向Broadlink的服務器(112.124.35.104)報告一次自己的狀態。可稱之為在線狀態報告。
實驗2:在4G網絡下(不用Wi-Fi),打開手機App對應的插座狀態界面

可以看到,大約每3秒,插座會向Broadlink的服務器(112.124.35.104)報告一次自己的開關狀態。當然,數據里還有在線狀態報告。通過包的長度很容易區分出來。
3秒的間隔應該是App端決定的,其實是App向Broadlink服務器詢問插座開關狀態,服務器再來問插座的。
局域網內抓包的問題
當手機在家里或在家外時,控制智能插座的原理是不一樣的。手機和插座在同一個局域網內時,它們是直接通訊,不需要借助於服務器的。
但在無線路由器上,其實是抓不到兩個Wi-Fi設備之間的通訊的。也許這些通訊由Wi-Fi硬件直接處理,不經過路由器的系統(驅動)。而且我試了,一方接在2.4G上,另一方接在5G上,也是一樣抓不到數據。
要抓取局域網內的兩個無線設備的通訊,傳統的辦法是把PC變成AP,讓它們的流量經過PC,然后用抓包軟件抓取。但這需要對設備重新部署、配置,比較折騰。
用無線網卡的monitor模式,使用Wi-Fi sniffer,也是一種選擇。但對於加密的無線網絡,比較麻煩。而且是從數據鏈路層分析應用層的數據,略感舍近求遠。
因為無線路由器上可以抓到局域網內有線設備和無線設備之間的通訊,所以還有另一個選擇:把手機變成有線的!
Android模擬器Genymotion
在PC上運行Android模擬器,我們就有了一個連在有線網絡上的手機了(前提當然是PC連在有線網絡上),從而可以繼續在無線路由器上抓包。
Android的模擬器有不少,我一般用Genymotion。Genymotion默認不支持ARM,但有好人弄了翻譯器。新版的Genymotion好像只在Android 6.0, 5.0上有翻譯器的支持。
當然,如果App支持x86架構,或與架構無關(純Java的),也是不需要ARM翻譯器的。但Broadlink App(易控)不是這樣的。

最后,Broadlink App能在Android 6.0的模擬器上正常運行。

另外,在Genymotion的設置中使用網橋模式,這樣,模擬器和Broadlink設備在同一網段。
局域網內行為研究
實驗3:在局域網內,Android模擬器上點擊開/關時,在OpenWRT上用tcpdump抓包

這些包里有3秒一次的開關狀態包。都是QUIC協議114字節。根據時間的周期性,可以看出哪些包是對應於開關控制的,比如上圖中的第2和第4個包。
為了重新發送這些數據包,寫了一個簡單的Python腳本sendpcap.py,對pcap文件進行簡單解析,主要是確定每個包的分隔,哪些是頭部,哪些是Payload,並可以發送指定序號的一個或多個包。
實驗4:在局域網內,重新發送pcap里的某個指定的UDP包,可以控制SP插座的開和關。
命令:sendpcap.py sp3 sp3-lan-phone-onoff.pcap 2
發送第2個包會開啟插座。

盡管每個包的數據不完全一樣,但這些包都可以用於控制插座。實測一年以后還有效(當然,只對於同樣網絡環境下的同一個設備)。
所以,對每個設備采集一段樣本數據,確定哪個包是控制開的,哪個包是控制關的,就可以實現對不同插座的自主控制了。
遠程行為研究
那么,這種重放機制對於遠程控制插座是否有效呢?
對於遠程交互,由於家里路由器上收到的只是進入設備的數據,而且,有些交互數據不一定會流入設備(也許是和Broadlink服務器交互)。所以,需要把抓包環境搭建在遠程端,抓獲遠程手機端的流出數據。
其實,在root的Android上也可以安裝tcpdump的。更好的是,Genymotion的Android已經自帶tcpdump了。
實驗5:在遠程網絡上,在Android模擬器上通過tcpdump抓包
命令:tcpdump -i eth1 -U -c 300 -vvv -w xxx.pcap

結果出乎意料,沒有任何直接指向家里的數據流,只有和Broadlink服務器的數據往來。

用同樣的方法,我們可以重發這些數據包。下圖中,數據包128對應於關播座,154對應於開插座。
實驗6:在遠程網絡上,通過重新發送pcap里的某個指定的包,可以控制家中的SP插座的開和關
命令:sendpcap.py 112.124.42.42 xxx.pcap 154

就這么輕松,發一個獨立的數據包給Broadlink的服務器就能控制家里的插座了,沒有任何上下文,數據也不會過期(實測一天之后也可以用)。
結語
有了基於OpenWRT的無線路由器,或基於Genymotion的Android模擬器,我們便可以很容易地在路由器或Android上用tcpdump抓取Broadlink SP設備的網絡數據包,從而分析其協議。

在局域網內控制Broadlink插座,並不需要Broadlink服務器的參與;而遠程控制插座,則都要借助於服務器。
重新發送截獲的 UDP/QUIC數據包就可以控制插座。不管是SP2,還是SP mini,不管是局域網,還是遠程的,都可以。但必須用在對應環境下、對應設備的數據包。對同一設備,每次抓獲的數據包都不完全相同,但用任何一個都有效,且不會過期,沒有會話上下文。
可見,這個安全性是很低的,形象地說,就是“裸奔”。只要在網絡上截獲發往Broadlink服務器或SP設備的UDP包,便很容易實現“重放攻擊”。當然,我們也可以用這一原理來自主地控制插座。比如,我曾用程控電源給鋰電池充電,當樹莓派檢測到電流或電壓達到一定值時,便從樹莓派上發UDP包關閉插座,從而徹底關閉程控電源; 當電壓過低時,便發包打開電源充電。這些,是用手機App無法整合的。
所以,這事有兩面性:不安全,但便利。
參考
- broadlink的智能插座sp2簡單分析. 沒有去驗證這篇文章中的抓包方式,只是從這篇文章得知重放攻擊的可行性。另一方面說明3年來,Broadlink的這一不安全的方式並沒有改進。
- 博聯易控App下載. 當前最新的版本確定可以在Genymition的Android模擬器上運行,但需要ARM翻譯器。
作者:蘿卜頭實驗室
鏈接:https://www.jianshu.com/p/028b10bc3dd1
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。