去年我買了一個新的冷凝式鍋爐(家用取暖產品),因而考慮上面必須有一個「智能恆溫器」,而選擇也不少,包括Google Nest、 Hive(英國自然氣公司設計的) 以及伍斯特·博世‘Wave’。但最終仍是選擇了後者。html
最後它被安裝在家中樓梯下面的牆上,並利用電線鏈接到設備上。正如你所看到的上面有一個觸摸面板,你能夠在上面調整恆溫器的參數,固然你也能夠在上面看到溫度以及蓄水狀況,而你也能夠切換自動模式來自動加熱,其實這裏最應該關心的是設備的工做狀態。若是想要使用相似定時之類的功能,就不得不用到移動應用程序了,就像這樣。java
看起來似曾相識吧?也許你也有一款應用程序的主頁面和這個看起來很像,固然你也能夠設置更高級的功能,好比定時等。python
對於目前仍是再使用伍斯特恆溫(調節)器,它能夠經過手機上的應用程序來進行定時功能的設置。固然這裏面還有很多其它高級的功能,例如這個功能「optimisation」,系統能夠根據你室內溫度的狀況來自動調節,來維持你選擇的溫度,而這個時候你可外出遊玩或者作一些別的事情。linux
不管怎麼樣,當我第一次接觸這個設備的時候,就開始安裝了應用程序,這樣就能夠監控該設備了。而做者理想的狀況是經過一個Python腳本程序來完成這個功能,但設備官網上沒有這樣的程序。做者後來又打電話給客服人員,客服人員稱沒有這樣的程序提供給做者。因而做者開始分析設備,並使用Python腳本程序來完成這些工做。android
因而開始分析設備來完成須要作的工做,首先須要知道的一點就是應用程序會將一些設備狀況以及信息發送給遠程的服務器(多是有效監控設備),而後再將反饋信息回傳到恆溫器,反之亦然。這就意味着能夠在不一樣的地方且沒必要經過同一個無線網絡就能夠完成對設備的控制。固然設備也能夠鏈接在家用電腦上,因此任何開放的端口都是須要經過防火牆纔可以和服務器鏈接的。git
在查看產品信息的時候發現了硬件以及軟件版本信息,包括該設備使用的開源軟件信息,打開後發現了開源軟件包列表以及各類許可協議,包括github
AndroidPlot-開源圖表庫web
Guava-一個 Google 的基於java1.6的類庫集合的擴展項目chrome
XMP Toolkit -可擴展元數據管理平臺json
Smack-一個開源,易於使用的XMPP(jabber)客戶端類庫
JSR305 Expert Group-代碼缺陷檢測(Java)
Lucent technologies-原文做者沒有註明
Chromium -Google 的chrome瀏覽器
Takayua OOURA-Ooura Mathematical(數學)軟件
Eigen-C++矩陣處理工具
libresample-數據重採樣(主要是音頻)工具
這樣你就能夠看到確實存在基於標準通用標記語言的子集XML的協議,基於XMPP的應用具備超強的可擴展性。通過擴展之後的XMPP能夠經過發送擴展的信息來處理用戶的需求,以及在XMPP的頂端創建如內容發佈系統和基於地址的服務等應用程序,同時XMPP提供一個通用的可擴展的框架來交換XML數據,用於準實時消息和出席信息以及請求-響應服務。而XMPP可用於服務類實時通信、表示和需求響應服務中的XML數據元流式傳輸。前面那個圖表庫的部分與此次工做沒有太大關聯,而對於數學軟件部分能夠作出這樣一個猜想,即利用這一點能夠完成一些高級功能的應用。
如今咱們能夠清楚了XMPP協議很重要,可是目前須要發送數據以及接收數據是什麼狀況,因而打開Wireshark軟件,而後監控流量信息,而後進行協議過濾,以後就會看到這個
好吧,如今這些證實個人猜想是正確的。安裝在手機上的設備應用程序傳輸信息使用的是XMPP協議(本地IP92.168.0.42),博世設備的服務器(wa2-mz36-qrmzh6.bosch.de)。如今就清楚協議具體是什麼狀況了。
而後壞消息是,出現了STARTTLS,能夠看出這是一個電子郵件設置對話框,同時這也是一個 POP3/IMAP/SMTP 服務安全選項。基本上能夠說是「傳輸層安全協議」,能夠說成是「我想從如今開始對這段對話進行加密,能夠嗎」(固然這也是一個參考,有些通訊能夠一開始就加密來確保通訊安全),固然設備的服務器能夠繼續運行,而如今就已經看到了 TLS安全協議,而後就能夠移動設備來發送信息了。
固然咱們沒有看到任何的明文信息,這些信息都是加密過的,例如這樣80414a90ca64968de3a0acc5eb1b50108bbc5b26973626daaa…,這些信息都不是頗有用的。
上面已經對 XMPP協議以及TLS安全協議進行了分析,但因爲作了加密處理因此咱們看不到信息內容。想要解密的話,須要完成一箇中間人攻擊,在攻擊中將會截取以及分析信息的內容,在這裏雖然被稱爲「攻擊」,可是用的手機鏈接的網絡是本身的,因此這裏算是安全測試。
這裏將會用到一個工具sslsplit,而在這裏我沒法利用sslsplit 來分析 STARTTLS(前文有對應,STARTTLS出現,而後利用TLS安全協議通訊)。
開始搭建linux 服務器(NAT轉換)-它工做起來像是路由器。同時也意味着我能夠在網絡上使用其它設備並將Linux做爲網關服務器(NAT轉換),
我在服務器上建立了服務器自簽名根證書,而這個證書是能夠信任的。
我將這個證書建立在了一個備用的安卓手機上,經過手機鏈接WiFi最後將Linux做爲網關服務器。最後做者測試了一下,能夠經過手機訪問網絡,而後全部的通訊都通過了服務器。
而後當我在使用設備應用程序的時候,手機鏈接服務器,也就是說全部的通訊都鏈接個人服務器而後在鏈接到廠商那邊的服務器,固然證書是必不可少的。
如今咱們已經建立了證書,配置了網絡,咱們須要開始解密信息了。正如上面所述,開始使用SSLSplit,可是這款工具彷佛不能應對STARTTLS,因此須要另一個解決途徑。幸運的是,我又發現了一款工具starttls-mitm,值得注意的是它僅僅有80行Python程序代碼,但可能功能上比一些相對複雜的工具要少,好比SSLSplit。可是這也都不重要,這就是我想要的。它甚至默認支持XMPP協議。
因此如今能夠經過指令來運行 starttls-mitm(基本上是密匙、證書等),如今就能夠分析未加密前的 STARTTLS,或者解密已加密的 STARTTLS ,若是咱們分析已經運行的應用程序會獲得什麼?
好吧,如今咱們利用starttls-mitm來分析一下登陸信息看看它在作什麼
LISTENER ready on port 8443
CLIENT CONNECT from: (’192.168.0.42′, 57913)
RELAYING
咱們獲得的初始信息
C->S 129 '<stream:stream to="wa2-mz36-qrmzh6.bosch.de" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">'
S->C 442 '
至關明顯,C->S是客戶端發送信息到服務器的意思,S->C意思就是剛剛那個反過來(數字表明信息的長度),這些也是剛剛分析 XMPP協議的結果,咱們以前在Wireshark也看到了這些,然而咱們看見了更有趣的事情。
C->S 51 '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>'
S->C 50 '<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>'
Wrapping sockets.
STARTTLS驗證信息發送,服務器會發出響應PROCEED,starttls-mitm分析以後會有提示「‘wrapping sockets」(而這一點也表示已經能夠解密通訊信息了)
而這裏我會跳過TLS協議的握手過程,直接切入到XMPP協議部分。我沒有分析XMPP協議的經驗,而info/query也是表明握手過程的一部分,整個過程都是在交流信息好比它們是誰,作什麼的等等,每一部分完成以後都會發出消息「presence」(xmpp甚至能夠被看作是即時通信協議,就至關於你在使用即時通信軟件,發出是否在線等信息)
C->S 110 '<iq id="lj8Vq-1" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>70</resource></bind></iq>'
S->C 188 '<iq type="result" id="lj8Vq-1" to="wa2-mz36-qrmzh6.bosch.de/260d2859"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>rrccontact_458921440@wa2-mz36-qrmzh6.bosch.de/70</jid></bind></iq>'
C->S 87 '<iq id="lj8Vq-2" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>'
S->C 86 '<iq type="result" id="lj8Vq-2" to="rrccontact_458921440@wa2-mz36-qrmzh6.bosch.de/70"/>'
C->S 74 '<iq id="lj8Vq-3" type="get"><query xmlns="jabber:iq:roster" ></query></iq>'
S->C 123 '<iq type="result" id="lj8Vq-3" to="rrccontact_458921440@wa2-mz36-qrmzh6.bosch.de/70"><query xmlns="jabber:iq:roster"/></iq>'
C->S 34 '<presence id="lj8Vq-4"></presence>'
C->S 34 '<presence id="lj8Vq-5"></presence>'
如今信息都已經處理好了,下面是客戶端(手機應用程序)到服務器之間的信息
C->S 162 '<message id="lj8Vq-6" to="rrcgateway_458921440@wa2-mz36-qrmzh6.bosch.de" type="chat"><body>GET /ecus/rrc/uiStatus HTTP /1.0\nUser-Agent: NefitEasy</body></message>'
而這基本上就是一個http GET請求並用到了XMPP 協議,而在應用程序「home screen」選項下,你能夠看到主頁面以及用戶設備信息(當前的溫度、溼度),如今咱們就能夠看到服務器的響應信息了
S->C 904 '<message to="rrccontact_458921440@wa2-mz36-qrmzh6.bosch.de/70" type="chat" xml:lang="en" from="rrcgateway_458921440@wa2-mz36-qrmzh6.bosch.de/RRC-RestApi"><body>HTTP/1.0 200 OK\nContent-Length: 640\nContent-Type: application/json\nconnection: close\n\n5EBW5RuFo7QojD4F1Uv0kOde1MbeVA46P3RDX6ZEYKaKkbLxanqVR2I8ceuQNbxkgkfzeLgg6D5ypF9jo7yGVRbR/ydf4L4MMTHxvdxBubG5HhiVqJgSc2+7iPvhcWvRZrRKBEMiz8vAsd5JleS4CoTmbN0vV7kHgO2uVeuxtN5ZDsk3/cZpxiTvvaXWlCQGOavCLe55yQqmm3zpGoNFolGPTNC1MVuk00wpf6nbS7sFaRXSmpGQeGAfGNxSxfVPhWZtWRP3/ETi1Z+ozspBO8JZRAzeP8j0fJrBe9u+kDQJNXiMkgzyWb6Il6roSBWWgwYuepGYf/dSR9YygF6lrV+iQdZdyF08ZIgcNY5g5XWtm4LdH8SO+TZpP9aocLUVR1pmFM6m19MKP+spMg8gwPm6L9YuWSvd62KA8ASIQMtWbzFB6XjanGBQpVeMLI1Uzx4wWRaRaAG5qLTda9PpGk8K6LWOxHwtsuW/CDST/hE5jXvWqfVmrceUVqHz5Qcb0sjKRU5TOYA+JNigSf0Z4CIh7xD1t7bjJf9m6Wcyys/NkwZYryoQm99J2yH2khWXyd2DRETbsynr1AWrSRlStZ5H9ghPoYTqvKvgWsyMVTxbMOht86CzoufceI2W+Rr9</body></message>'
這看起來有些複雜不容易解釋,可是整理一下信息格式或許看起來更好一些。
HTTP/1.0 200 OK
Content-Length: 640
Content-Type: application/json
connection: close
5EBW5RuFo7QojD4F1Uv0kOde1MbeVA46P3RDX6ZEYKaKkbLxanqVR2I8ceuQNbxkgkfzeLgg6D5ypF9jo7yGVRbR/ydf4L4MMTHxvdxBubG5HhiVqJgSc2+7iPvhcWvRZrRKBEMiz8vAsd5JleS4CoTmbN0vV7kHgO2uVeuxtN5ZDsk3/cZpxiTvvaXWlCQGOavCLe55yQqmm3zpGoNFolGPTNC1MVuk00wpf6nbS7sFaRXSmpGQeGAfGNxSxfVPhWZtWRP3/ETi1Z+ozspBO8JZRAzeP8j0fJrBe9u+kDQJNXiMkgzyWb6Il6roSBWWgwYuepGYf/dSR9YygF6lrV+iQdZdyF08ZIgcNY5g5XWtm4LdH8SO+TZpP9aocLUVR1pmFM6m19MKP+spMg8gwPm6L9YuWSvd62KA8ASIQMtWbzFB6XjanGBQpVeMLI1Uzx4wWRaRaAG5qLTda9PpGk8K6LWOxHwtsuW/CDST/hE5jXvWqfVmrceUVqHz5Qcb0sjKRU5TOYA+JNigSf0Z4CIh7xD1t7bjJf9m6Wcyys/NkwZYryoQm99J2yH2khWXyd2DRETbsynr1AWrSRlStZ5H9ghPoYTqvKvgWsyMVTxbMOht86CzoufceI2W+Rr9
它彷佛看起來像是HTTP標準的響應,但主要的消息看起來像是某種編碼格式,我認爲解碼以後會出現例如 JSON 、XML或者另外的一些東西,可是該這麼作呢?
我嘗試作了很多事情( MD五、Base64解碼 ),但彷佛沒有起做用。因而我開始放下手頭的工做,思考它。當我在工做的時候,突然意識到數據是加密的。當你想要訪問設備代碼時候還須要注意你的登陸密碼(第一次登陸設備程序時候設置的),固然解密就須要知道加密方式是什麼樣子的,因而須要用到反編譯器。
爲了瞭解設備的程序,就須要分析其apk文件,經過反編譯的方式來查看代碼。我用到的工具是 Android APK Decompiler,值得注意的是獲得了通俗易懂的Java程序代碼。(這裏面還有一些goto語句,並設置了合理的變量名)
做者表示顯然徹底解釋加密以及解密詳細狀況是很是困難的,包括下面做者的 Python程序代碼,但做者作了一個簡短的解釋,主要的加密是AES( ECB),經過 MD5 sums命令(訪問程序代碼整合)生成密鑰、密碼以及secret(應用程序中的硬編碼)
def encode(s):
abyte1 = get_md5(access + secret)
abyte2 = get_md5(secret + password)
key = abyte1 + abyte2
a = AES.new(key)
a = AES.new(key, AES.MODE_ECB)
res = a.encrypt(s)
encoded = base64.b64encode(res)
return encoded
def decode(data):
decoded = base64.b64decode(data)
abyte1 = get_md5(access + secret)
abyte2 = get_md5(secret + password)
key = abyte1 + abyte2
a = AES.new(key)
a = AES.new(key, AES.MODE_ECB)
res = a.decrypt(decoded)
return res
利用這些函數就能夠在GET /ecus/rrc/uiStatus響應得到信息,而後就看到了這些
{'id': '/ecus/rrc/uiStatus',
'recordable': 0,
'type': 'uiUpdate',
'value': {'ARS': 'init',
'BAI': 'CH',
'BBE': 'false',
'BLE': 'false',
'BMR': 'false',
'CPM': 'auto',
'CSP': '31',
'CTD': '2014-12-26T12:34:27+00:00 Fr',
'CTR': 'room',
'DAS': 'off',
'DHW': 'on',
'ESI': 'off',
'FPA': 'off',
'HED_DB': '',
'HED_DEV': 'false',
'HED_EN': 'false',
'HMD': 'off',
'IHS': 'ok',
'IHT': '16.70',
'MMT': '15.5',
'PMR': 'false',
'RS': 'off',
'TAS': 'off',
'TOD': '0',
'TOR': 'on',
'TOT': '17.0',
'TSP': '17.0',
'UMD': 'clock'},
'writeable': 0}
固然信息不可能馬上顯示出具體含義(其中三個變量名設置比較好),固然裏面仍是有一些比較明顯的,好比CTD(可能表明像當前時間/日期)、DHW(生活用熱水,在暖通領域內牽涉到建築熱負荷時會用到,通常會用日平均每人用量(因建築功能而異)與人數來肯定)。在這一部分,我分析了全部狀態信息,並利用了溫度監控系統,下面將會進行一些其它的事情(設置新溫度等),而後再來看看做者的python 庫。
在上面咱們介紹了通訊加密的信息,以及當前系統的狀態。固然若是能利用Python程序設置溫度、以及定時時間等,而這些就是要作的事情。我將會再一次的使用「中間人攻擊」來監控應用程序。當發現溫度改變的時候,你就會出現如下信息。
<message id="lj8Vq-31" to="rrcgateway_458921440@wa2-mz36-qrmzh6.bosch.de"
type="chat">
<subject>/heatingCircuits/hc1/manualTempOverride/temperature</subject><body>PUT /heatingCircuits/hc1/manualTempOverride/temperature HTTP:/1.0\nContent-Type: application/json\nContent-Length: 25\nUser-Agent: NefitEasy\n\n\n\nXmuIR7wCfDZpPrPkrb/CqQ==\n</body></message>
在整合XMPP協議(去掉頭信息)以後,你就會看到這個
PUT /heatingCircuits/hc1/manualTempOverride/temperature
HTTP:/1.0
Content-Type: application/json
Content-Length: 25
User-Agent: NefitEasy
XmuIR7wCfDZpPrPkrb/CqQ==
在獲得的信息最後,解碼能夠獲得下面信息
{"value":16}\x00\x00\x00\x00
這看起來像是JSON,最後那些補位數據主要是出於對加密程序數據類型的長度考慮的。這可能和個人設置有關係,我將溫度設置在了16度。
若是我設置了不一樣的數據(不一樣的數字信息),而後溫度預設定會改變嗎?
固然須要改變溫度,取決於你選擇的模式,這裏有兩種模式可供選擇,當前狀態信息(UMD)會告訴你處於哪一種模式,手動或定時模式。若是處於前面那種模式,你能夠發送一個簡單的 PUT 請求/heatingCircuits/hc1/temperatureRoomManual以及JSON({「value」:21}),這樣作主要是就取決於你想要的溫度。
若是選擇後者那種模式,你就須要設置「override temperature」(一個 PUT請求/heatingCircuits/hc1/manualTempOverride/temperature),而後須要設置「temperature override function」(一個PUT請求/heatingCircuits/hc1/manualTempOverride/status以及 JSON {「value」: 「on」})。
若是你想要改變模式能夠向 /heatingCircuits/hc1/usermode( JSON {「value」: 「clock」} 或{「value」:」manual」})發出一個 PUT請求,固然你會獲得一個迴應,只要不出現錯誤信息,你會看到這些信息內容。
No Content
Content-Type: application/json
connection: close
而也能夠經過發送其它一些信息來作一些更復雜的事情(例如改變定時器程序),但做者表示尚未去測試這些事情。但這些大體相同,他們可能利用了更復雜的JSON payload,並須要更多的信息來確認。如今我能夠控制設備的基本狀態(模式以及溫度)。
做者到這裏並無說起太多有關Python的事情,但做者表示本身的大部分測試工做都是利用了 基於Python的sleekxmpp庫,做者表示能夠設計一個真正的有限狀態機,來收發信息。而這些工做模式都是異步模式,看起來真的不容易。
因此爲了發送信息以及解密文件做者建立了一個BaseWaveMessageBot class文件,並能夠作出一些簡單的錯誤處理。因爲建立的文件有不少不一樣的內容,因而做者又在裏面添加了一些新的內容(StatusBot 以及SetBot),利用它能夠發出信息以及作出響應。做者將這些文件稱爲WaveThermo,做者須要在裏面加入更多的內容,更新一些新功能。
做者提供的程序(點擊我)
而做者只是在溫控器上面測試過它,固然你能夠利用做者的方法再結合實際狀況去作出更多的方案。