BlueBorne遠端程式碼執行漏洞Poc實戰(CVE-2017-0781)

freakish發表於2017-12-12

BlueBorne遠端程式碼執行漏洞Poc實戰(CVE-2017-0781)

  • 前幾天,一個名為Armis的公司釋出了Android裝置上的一個藍芽遠端程式碼執行漏洞(CVE-2017-0781)的Poc,漏洞命名為BlueBorne,儘管BlueBorne漏洞涉及到了8個漏洞點,但是這個Poc只用了其中的2個就達到了利用的目的。
  • 整個利用過程分為2個階段,Poc先是使用了記憶體洩露漏洞(CVE-2017-0785)獲取記憶體地址並且繞過ASLR保護,透過這個手段就可以順暢的呼叫libc.system函式並且在手機裝置上執行程式碼,在這個例子中最後就是得到一個反彈Shell。
  • Armis公司釋出的Poc是針對搭載了Android7.1.2系統的Pixel和Nexus 5X 手機,如果要把Poc程式碼移植到其他機型上,只需要修改相應的libc和bluetooth的偏移即可。
  • 本文稍後會說一下,在其他機型上也可以使用這個Poc,就是比較麻煩,比如在6.0.1機型上測試這個Poc就比較麻煩,一個是利用過程複雜了,另外一個Poc需要修改的地方也多一些。
  • 在進行下面的步驟之前,請先確保你的手機已經root

下載相關的庫檔案

  • 第一步是從手機上把需要分析的庫檔案下載下來,稍後要使用IDA或者Radare進行分析,請參考下面的命令:
    1. $ adb pull /system/lib/hw/bluetooth.default.so
    2. $ adb pull /system/lib/libc.so

libc.system函式

  • 使用Radware開啟libc.so然後尋找system這個函式,我這裡的地址是0x3ea04,這裡改下Poc中相關變數 LIBC_TEXT_STSTEM_OFFSET = 0x3ea04 +1

記憶體洩露

  • 透過記憶體洩露這個漏洞我們可以知道libc.so和bluetooth.default.so的載入位置
  • 在我們分析的這個機型中,我們所需要的幾個關鍵點在記憶體中的地址並不是固定不變的,所以我們需要在記憶體中尋找出這些關鍵位置,然後我們就可以依據這些位置資訊進一步修改利用程式碼:
  • 因為Android程式每次重啟之後上述的地址值都會發生改變,所以為了方便,我們在開始之前需要先對com.android.bluetooth.process 程式做一個記憶體映象,可以參考下面的命令進行操作:
  • 這裡我們在洩露的記憶體段中我們搜尋一個取值範圍在0xb376f000和0xb38b5000之間的一個數值,為了省事,我直接使用現成的指令碼(CVE-2017-0785.py)來操作:
  • 現在搜尋有了結果,我這裡使用 0xb38b3d80(180行) ,使用這個值我們計算出偏移值,然後更新BLUETOOTH_BSS_SOME_VAR_OFFSET這個變數,並注意同時更新搜尋結果的那個資料來源(原文不太確定:without forgetting also to update the element of the result table from which we have obtained this value)。
  • 下面我們接著來看下怎麼獲取libc的載入地址:
  • 在上面的搜尋結果中選取任意一個值,然後計算出偏移並更新變數LIBC_SOME_BLX_OFFSET
  • 到這裡為止,基本上就可以不用去管ASLR保護了

小技巧

  • 我這裡推薦一個小指令碼,可以列印洩露的變數 result 的內容:
  • 或者還有一個方法可以嘗試,就是你可以嘗試多做幾次記憶體快照,然後對這幾個記憶體快照進行對比,找到其中幾處記憶體值不變的幾個點作為參考點來進行相對定位,這也是一個不錯的方法,我直接上圖:

REMOTE_NAME變數

  • 這個變數包含了建立藍芽連線的裝置名稱,在7.1.2版本的Poc裡面,使用這個變數來存放system函式的地址和Bash命令列,有關這個變數的細節我們後面再說。
  • 我這裡使用包含PEDA-ARM和searchmem元件的GDB來獲取這個變數的記憶體地址,最後計算出來的偏移地址儲存在BSS_ACL_REMOTE_NAME_OFFSET中,我給出我的操作示意圖:

攻擊載荷(Payload)

  • 從Armis公司的Poc技術文件(https://go.armis.com/hubfs/BlueBorne - Android Exploit.pdf)細節中我們可以知道,如果我們使用REMOTE_NAME的值來覆蓋R0, btu_hci_msg_process這個函式將會跳轉到[REMOTE_NAME+8]的位置,而不是去執行R0指向的位置,請看下面這段程式碼:
  • 這樣一來,我們可以把system函式的地址放到REMOTE_NAME+8的位置,然後REMOTE_NAME開始的位置放上要執行的BASH命令,但是這樣就有一個問題,我們的system函式地址插在了命令的中間去了,這樣命令就會報錯了。Armis給出來這樣的解決辦法,就是把要執行的命令用分號分成2條,前面一條裡面包含了system的地址,後面一條包含了完整的bash命令,這樣前面的那條命令報錯就讓他報錯好了,目的我們達到了,最終的結果是這樣的:
  • 但是,如果你的測試環境是Android6.0.1,你再按照上面的步驟過一遍就發現不行了,因為庫函式里面沒有上述那些函式。但是也不用放棄,因為我發現在可溢位的函式里面,也有可以透過R0來控制執行流程的函式,這裡我選擇000f1e36處的函式,看圖:
  • 透過下面這些指令組,我們就可以透過R0來控制跳轉:
  • 程式碼簡化一下,就像這樣:
  • 為了達到我們的目的,我們這裡就需要三個指標來控制跳轉,一個指標來控制R0,而上面的那個方法只需要一個system函式地址就行了,好了,來看下REMOTE_NAME中可以存放的Payload的結構吧:

執行測試

  • 上面的這些工作全部做完之後,我們就可以來測試了,注意,為了達到測試效果,有時候我們需要多次執行測試程式才能達到漏洞利用的效果:

相關程式碼

致謝

譯者

相關文章