當前位置:
首頁 > 最新 > 新型「敲竹杠」木馬設置障眼法反偵察 360巧破天書密碼

新型「敲竹杠」木馬設置障眼法反偵察 360巧破天書密碼

前些天,armis爆出了一系列藍牙的漏洞,無接觸無感知接管系統的能力有點可怕,而且基本上影響所有的藍牙設備,危害不可估量,可以看這裡(https://www.armis.com/blueborne/ )來了解一下它的逆天能力:只要手機開啟了藍牙,就可能被遠程控制。現在手機這麼多,利用這個漏洞寫出蠕蟲化的工具,那麼可能又是一個手機版的低配wannacry了。我們360Vulpecker Team在了解到這些相關信息後,快速進行了跟進分析。 armis給出了他們的whitepaper,對藍牙架構和這幾個漏洞的分析可以說非常詳盡了,先膜一發。不過他們沒有給出這些漏洞的PoC或者是exp,只給了一個針對Android的「BlueBorne檢測app",但是逆向這個發現僅僅是檢測了系統的補丁日期。於是我來拾一波牙慧,把這幾個漏洞再分析一下,然後把poc編寫出來:

以上PoC代碼均在

https://github.com/marsyy/littl_tools/tree/master/bluetooth

由於也是因為這幾個漏洞才從零開始搞藍牙,所以應該有些分析不到位的地方,還請各路大牛斧正。

1、 藍牙架構及代碼分布

這裡首先應該祭出armis的paper里的圖:

1圖上把藍牙的各個層次關係描述得很詳盡,不過我們這裡暫時只需要關心這麼幾層:HCI,L2CAP,BNEP,SDP。BNEP和SDP是比較上層的服務,HCI在最底層,直接和藍牙設備打交道。而承載在藍牙服務和底層設備之間的橋樑,也就是L2CAP層了。每一層都有它協議規定的數據組織結構,所有層的數據包組合在一起,就是一個完整的藍牙包(一個SDP包為例):

2雖然協議規定的架構是圖上說的那樣,但是具體實現是有不同的,Linux用的BlueZ,而現在的Android用的BlueDroid,也就針對這兩種架構說一說代碼的具體分布。

BlueZ

在Linux里,用的是BlueZ架構,由bluetoothd來提供BNEP,SDP這些比較上層的服務,而L2CAP層則是放在內核裡面。對於BlueZ我們對SDP和L2CAP挨個分析。

實現SDP服務的代碼在代碼目錄的/src/sdp,其中sdp-client.c是它的客戶端,sdp-server.c是它的服務端。我們要分析的漏洞都是遠程的漏洞,所以問題是出在服務端裡面,我們重點關注服務端。而服務端最核心的代碼,應該是它對接受到的數據包的處理的過程,這個過程由sdp-request.c來實現。當L2CAP層有SDP數據後,會觸發sdp-server.c的io_session_event函數,來獲取這個數據包,交由sdp-request.c的handle_request函數處理(怎麼處理的,後續漏洞分析的時候再講):

2, L2CAP層的代碼在內核里,這裡我以Linux 4.2.8這份代碼為例。l2cap層主要由 /net/bluetooth/l2capcore.c和/net/bluetooth/l2cap_sock.c來實現。l2cap_core.c實現了L2CAP協議的主要內容,l2cap_sock.c通過註冊sock協議的方式提供了這一層針對userspace的介面。同樣的我們關心一個L2CAP對接受到數據包後的處理過程,L2CAP的數據是由HCI層傳過來的,在hci_core.c的hci_rx_work函數里

收到數據後,會判斷pkt_type,符合L2CAP層的type是HCI_ACLDATA_PKT,函數會走到hci_acldata_packet,這個函數會把HCI的數據剝離之後,把L2CAP數據交給L2CAP層的l2cap_recv_acldata:

同樣的,對於L2CAP層對數據的細緻處理,我們還是等後續和漏洞來一塊進行分析。

BlueDroid

在現在的Android里,用的是BlueDroid架構。這個和BlueZ架構有很大不同的一點是:BlueDroid將L2CAP層放在了userspace。SDP,BNEP,L2CAP統統都由com.android.bluetooth這個進程管理。而BlueDroid代碼的核心目錄在Android源碼目錄下的 /sytem/bt ,這個目錄的核心產物是bluetooth.default.so,這個so集成所有Android藍牙相關的服務,而且這個so沒有導出任何相關介面函數,只導出了幾個協議相關的全局變數供使用,所以想根據so來本地檢測本機是否有BlueDrone漏洞,是一件比較困難的事情。對於BlueDroid,由於android的幾個漏洞出在BNEP服務和SDP服務,所以也就主要就針對這兩塊。值得注意的是,在Android里,不論是64位還是32位的系統,這個bluetooth.default.so都是用的32位的。文章里這部分代碼都基於Android7.1.2的源碼。

1,BlueDroid的SDP服務的代碼,在/system/bt/stack/sdp 文件夾里,其中sdp服務端對數據包的處理由sdp-server.c實現。SDP連接建立起來後,在收到SDP數據包之後呢,會觸發回調函數sdp_data_ind,這個函數會把數據包交個sdp-server.c的sdp_server_handle_client_req函數進行處理:

BlueDroid的BNEP服務的代碼主要在/system/bt/stack/bnep/bnepmain.c。BNEP連接建立起來後,再收到BNEP的包,和SDP類似,會觸發回調函數bnep_data_ind,這個函數包含了所有對BNEP請求的處理,漏洞也是發生在這裡,具體的代碼我們後續會分析。

2 漏洞分析以及PoC寫法

藍牙的預備知識差不多了,主要是找數據包的入口。我們再基於漏洞和PoC的編寫過程來詳細分析其中的處理過程,和相關藍牙操作的代碼該怎麼寫。

這個是Linux L2CAP層的漏洞,那麼就是內核裡面的。先不著急看漏洞,先看L2CAP層如何工作。在一個L2CAP連接的過程中,我們抓取了它的數據包來分析,L2CAP是怎麼建立起連接的:

我們注意這麼幾個包: sent_infomation_request , send_connection_request, send_configure_request。抓包可以看到,在一次完整的L2CAP連接的建立過程中,發起連接的機器,會主動送出這麼幾個包。其中infomation_request是為了得到對方機器的名稱等信息,connection_request是為了建立L2CAP真正的連接,主要是為了確定雙方的CHANNEL ID,後續的數據包傳輸都要跟著這個channel id 走(圖上的SCID, DCID),這個channel也就是我們所說的連接。在connection_request處理完畢之後,連接狀態將變成 BT_CONNECT2 。隨後機器會發起configure_request,這一步就到了armis的paper第十頁所說的configuration process:

這個過程完成後,整個L2CAP層的連接也就建立完成。

從上述過程看,可以發現L2CAP層連接的建立,主要是對上述三個請求的發起和處理。而我們的漏洞,也其實就發生在configuration process。我們先分析接收端收到這三個請求後,處理的邏輯在哪裡,也就是我們前文提到的L2CAP對接受到的數據的處理過程:

1,在l2cap_recv_acldata接收到數據後,數據包會傳給l2cap_recv_frame

2,l2cap_recv_frame會取出檢查L2CAP的頭部數據,然後檢查根據頭部里的cid欄位,來選擇處理邏輯:

3,底層L2CAP的連接,cid固定是L2CAP_CID_SIGNALING,於是會走l2cap_sig_channel,l2cap_sig_channel得到的是剝離了頭部的L2CAP的數據,這一部將把數據里的cmd頭部解析並剝離,再傳給l2cap_bredr_sig_cmd進行處理:

到這裡,我們應該能得出L2CAP協議的數據結構:

圖11

4, 隨後數據進入到了l2cap_bredr_sig_cmd函數進行處理。這裡也就是處理L2CAP各種請求的核心函數了:

好了,接下來終於可以分析漏洞了。我們的漏洞發生在對L2CAP_CONFIG_RSP(config response)這個cmd的處理上。其實漏洞分析armis的paper已經寫的很詳盡了,我這裡也就權當翻譯了吧,然後再加點自己的理解。那麼來看l2cap_config_rsp:

當收到的數據包里,滿足result == L2CAP_CONF_PENDING,且自身的連接狀態conf_state == CONF_LOC_CONF_PEND的時候,會走到 l2cap_parse_conf_rsp函數里,而且傳過去的buf是個長度為64的數據,參數len ,參數rsp->data都是由包中的內容來任意確定。那麼在l2cap_parse_conf_rsp函數里:

仔細閱讀這個函數的代碼可以知道,這個函數的功能就是根據傳進來的包,來構造將要發出去的包。而數據的出口就是傳進去的64位元組大小的buf。但是對傳入的包的數據的長度並沒有做檢驗,那麼當len很大時,就會一直往出口buf里寫數據,比如有64個L2CAP_CONF_MTU類型的opt,那麼就會往buf里寫上64*(L2CAP_CONF_OPT_SIZE + 2)個位元組,那麼顯然這裡就發生了溢出。由於buf是棧上定義的數據結構,那麼這裡就是一個棧溢出。 不過值得注意的是,代碼要走進去,需要conf_state == CONF_LOC_CONF_PEND,這個狀態是在處理L2CAP_CONF_REQ數據包的時候設置的:

當收到L2CAP_CONF_REQ的包中包含有L2CAP_CONF_EFS類型的數據【1】,而且L2CAP_CONF_EFS數據的stype == L2CAP_SERV_NOTRAFIC【2】的時候,conf_state會被置CONF_LOC_CONF_PEND

到這裡,這個漏洞觸發的思路也就清楚了:

1,建立和目標機器的L2CAP 連接,這裡注意sock_type的選擇要是SOCK_RAW,如果不是,內核會自動幫我們完成sent_infomation_request, send_connection_request, send_configure_request這些操作,也就無法觸發目標機器的漏洞了。

2,建立SOCK_RAW連接,connect的時候,會自動完成sent_infomation_request的操作,不過這個不影響。

3,接下來我們需要完成send_connection_request操作,來確定SCID,DCID。完成這個操作的過程是發送合法的 L2CAP_CONN_REQ數據包。

4,接下來需要發送包含有L2CAP_CONF_EFS類型的數據,而且L2CAP_CONF_EFS數據的stype ==L2CAP_SERV_NOTRAFIC的L2CAP_CONF_REQ包,這一步是為了讓目標機器的conf_state變成CONF_LOC_CONF_PEND。

5,這裡就到了發送cmd_len很長的L2CAP_CONN_RSP包了。這個包的result欄位需要是L2CAP_CONF_PENDING。那麼這個包發過去之後,目標機器就內核棧溢出了,要麼重啟了,要麼死機了。

這個漏洞是這幾個漏洞里,觸發最難的。

這個漏洞是BlueZ的SDP服務里的信息泄露漏洞。這個不像L2CAP層的連接那麼複雜,主要就是上層服務,收到數據就進行處理。那麼我們也只需要關注處理的函數。 之前說過,BlueZ的SDP收到數據是從io_session_event開始。之後,數據的流向是:

有必要介紹一下SDP協議的數據結構: 它有一個sdp_pud_hdr的頭部,頭部數據里定義了PUD命令的類型,tid,以及pdu parameter的長度,然後就是具體的parameter。最後一個欄位是continuation state,當一個包發不完所要發送的數據的時候,這個欄位就會有效。對與這個欄位,BlueZ給了它一個定義:

對於遠程的連接,PDU命令類型只能是這三個:SDP_SVC_SEARCH_REQ, SDP_SVC_ATTR_REQ, SDP_SVC_SEARCH_ATTR_REQ。這個漏洞呢,出現在對SDP_SVC_SEARCH_ATTR_REQ命令的處理函數裡面 service_search_attr_req 。這個函數有點長,就直接說它幹了啥,不貼代碼了:

1, extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); 解析service search pattern(對應SDP協議數據結構圖)

2,max = getbe16(pdata); 獲得Maximu Attribute Byte

3,scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);解析Attribute ID list

4,if (sdp_cstate_get(pdata, data_left, &cstate) < 0) ;獲取continuation state狀態cstate,如果不為0,則將包里的continuation state數據複製給cstate.

漏洞發生在對cstate狀態不為0的時候的處理,我們重點看這部分的代碼:

sdp_get_cached_rsp函數其實是對cstate的timestamp值的檢驗,如何過這個檢驗之後再說。當代碼走到【1】處的memcpy時,由於cstate->maxBytesSent就是由數據包里的數據所控制,而且沒有做任何檢驗,所以這裡可以為任意的uint16t值。那麼很明顯,這裡就出現了一個對pResponse的越界讀的操作。而越界讀的數據還會通過SDP RESPONSE發送給攻擊方,那麼一個信息泄露就發生了。

寫這個poc需要注意sdp_get_cached_rsp的檢驗的繞過,那麼首先需要得到一個timestamp。當一次發送的包不足以發送完所有的數據的時候,會設置cstate狀態,所以如果我們發給服務端的包里,max欄位非常小,那麼服務端就會給我們回應一個帶cstate狀態的包,這裡面會有timestamp:

所以,我們的poc應該是這個步驟:

1,建立SDP連接。這裡我們的socket需要是SOCK_STREAM類型,而且connet的時候,addr的psm欄位要是0x0001。關於連接的PSM:

2,發送一個不帶cstate狀態的數據包,而且指定Maximu Attribute Byte的值非常小。這一步是為了讓服務端給我們返回一個帶timestamp的包。

3,接收這個帶timestamp的包,並將timestamp提取。

4,發送一個帶cstate狀態的數據包,cstate的timestamp是指定為提取出來的值,服務端memcpy的時候,則就會把pResponse+maxBytesSent的內容發送給我們,讀取這個數據包,則就獲取了泄露的數據。

CVE-2017-0785

這個漏洞也是SDP的信息泄露漏洞,不過是BlueDroid的。與BlueZ的那個是有些類似的。我們也從對SDP數據包的處理函數說起。 SDP數據包會通過sdp_data_ind函數送給sdp_server_handle_client_req。與BlueZ一樣,這個函數也會根據包中的pud_id來確定具體的處理函數。這個漏洞發生在對SDP_PDU_SERVICE_SEARCH_REQ命令的處理,對包內數據的解析與上文BlueZ中的大同小異,不過注意在BlueDroid中,cstate結構與BlueZ中有些不同:

這裡主要看漏洞:

,中代碼可以看出,變數num_rsp_handles的值,一定程度上可以由包中的Maximu Attribute Byte欄位控制。 中代碼是對帶cstate的包的處理,第一步是對大小的檢查,第二步是獲得cont_offset,然後對cont_offset進行檢查,第三步就到了 rem_handles = num_rsp_handles - cont_offset 可以思考一種情況,如果num_rsp_handles < cont_offset,那麼這個代碼就會發生整數的下溢,而num_rsp_handles在一定程度上我們可以控制,而且是可以控制它變成0,那麼只要cont_offset不為0,這裡就會發生整數下溢。發生下溢的結果給了rem_handles,而這個變數代表的是還需要發送的數據數。 在中,如果rem_handles是發生了下溢的結果,由於它是uint16_t類型,那麼它將變成一個很大的數,所以會走到pccb->cont_offset += cur_handles;,cur_handles是一個固定的值,那麼如果這個下溢的過程,發生很多次,pccb->cont_offset就會變得很大,那麼在5處,就會有一個對rsp_handles數組的越界讀的產生。

下面的操作可以讓這個越界讀發生:

1,發送一個不帶cstate的包, 而且Maximu Attribute Byte欄位設置的比較大。那麼結果就是rem_handles = num_rsp_handles,而由於max_replies比較大,所以num_rsp_handles會成為一個比較大的值。只要在中保證rem_handles> cur_handles,那麼pccb->cont_offset就會成為一個非0值cur_handles。這一步是為了使得pccb->cont_offset成為一個非0值。

2,接收服務端的回應包,這個回應包里的cstate欄位將會含有剛剛的pccb->cont_offset值,我們取得這個值。

3,發送一個帶cstate的包,cont_offset指定為剛剛提取的值,而且設置Maximu Attribute Byte欄位為0。那麼服務端收到這個包後,就會走到rem_handles = num_rsp_handles - cont_offset從而發生整數下溢,同時pccb->cont_offset又遞增一個cur_handles大小。

4,重複2和3的過程,那麼pccb->cont_offset將越來越大,從而在出發生越界讀,我們提取服務端返回的數據,就可以獲得泄露的信息的內容。

CVE-2017-0781

現在我們到了BNEP服務。BNEP的協議格式,下面兩張圖可以說明的很清楚:

BlueDroid中BNEP服務對於接受到的數據包的處理也不複雜:

1,解析得到BNEP_TYPE,得到extension位。

2,檢查連接狀態,如果已經連接則後續可以處理非BNEP_FRAME_CONTROL的包,如果沒有建立連接,則後續只處理BNEP_FRAME_CONTROL的包。

3,去BNEP_TYPE對應的處理函數進行處理。

4,對於BNEP_TYPE不是BNEP_FRAME_CONTROL而且有extension位的,還需要對extension的數據進行處理。

5,調用pan層的回調函數。

值得注意的是,BNEP連接真正建立起來,需要先處理一個合法的BNEP_FRAME_CONTROL數據包。 CVE-2017-0781正是連接還沒建立起來,在處理BNEP_FRAME_CONTROL時所發生的問題:

上述代碼中,malloc了一個remlen的大小,這個是和收到的數據包的長度相關的。可是memcpy的時候,卻是從pbcb->p_pending_data+1開始拷貝數據,那麼這裡會直接溢出一個sizeof(*(pbcb->p_pending_data))大小的內容。這個大小是8.所以只要代碼走到這,就會有一個8位元組大小的堆溢出。而要走到這,只需要過那個if的判斷條件,而這個if其實是對BNEP_SETUP_CONNECTION_REQUEST_MSG命令處理失敗後的錯誤處理函數。那麼只要發送一個錯誤的BNEP_SETUP_CONNECTION_REQUEST_MSG命令包,就可以進入到這段代碼了觸發堆溢出了。

所以我們得到poc的編寫過程:

1,建立BNEP連接,這個和SDP類似,只是需要指定PSM為BNEP對應的0x000F。

2,發送一個BNEPTYPE為BNEP_FRAME_CONTROL,extension欄位為1,ctrl_type為BNEP_SETUP_CONNECTION_REQUEST_MSG的錯誤的BNEP包:

上述代碼中,【1】的ext_len從數據包中獲得,沒有長度的檢查,可為任意值。而當control_type為一個非法值的時候,會走到【2】,那麼這裡就很有說法了,我們如果設置ext_len比較大,那麼這裡就會發生一個整數下溢。從而使得rem_len變成一個很大的uint16_t的值。這個值將會影響後續的處理:

上面的代碼中,【1】處將發生整數下溢出,使得rem_len成為一個很大的值(比如0xfffd),【2】處會將這個值賦值給p_buf->len。【3】處是回調函數處理這個p_buf,在BlueDroid中這個函數是pan_data_buf_ind_cb,這個函數會有一條路徑調到bta_pan_data_buf_ind_cback,而在這個函數中:

memcpy用到了我們傳進來的pbuf,而pbuf->len是剛剛下溢之後的很大的值,所以主要保證tBTA_PAN_DATA_PARAMS> pbuf->offset,這裡就會發生一次很大位元組的堆溢出。

代碼首先要走到extension的處理,這個的前提是連接狀態是BNEP_STATE_CONNECTED。而這個狀態的建立,需要服務端先接收一個正確的BNEP_SETUP_CONNECTION_REQUEST_MSG請求包,同時要想pan_data_buf_ind_cb調用到bta_pan_data_buf_ind_cback產生堆溢出,需要在建立連接的時候指定UUID為UUID_SERV_CLASS_PANU可以閱讀這兩個函數來找到這樣做的原因,這裡就不再貼代碼了。清楚這一點之後,我們就可以構造我們的poc了:

1,建立BNEP連接,這裡只是建立起初步的連接,conn_state還不是BNEP_STATE_CONNECTED,這一步通過connect實現

2,發送一個正確的BNEP_SETUP_CONNECTION_REQUEST_MSG請求包,同時指定UUID為UUID_SERV_CLASS_PANU。這個包將是這樣子:

3

這篇分析到這裡也就結束了,藍牙出漏洞是個比較危險的事情,希望沒有修補的能儘快修補,補丁鏈接如下:

CVE-2017-0785

CVE-2017-0781

CVE-2017-0782

確定自己是否有漏洞可以用我們提供的poc呀,關於藍牙漏洞的研究,也希望能和各位多多交流。

參考文檔:

1,https://www.armis.com/blueborne/

2,http://blog.csdn.net/rain0993/article/details/8533246

3,https://people.csail.mit.edu/albert/bluez-intro/index.html

4

360Vulpecker Team: 隸屬於360公司信息安全部,致力於保護公司所有Android App及手機的安全,同時專註於移動安全研究,研究重點為安卓APP安全和安卓OEM手機安全。 團隊定製了公司內部安卓產品安全開發規範,自主開發並維護了在線Android應用安全審計系統「360顯危鏡」,在大大提高工作效率的同時也為開發者提供了便捷的安全自測平台。同時研究發現了多個安卓系統上的通用型漏洞,如通用拒絕服務漏洞、「寄生獸」漏洞等,影響範圍幾乎包括市面上所有應用。 該團隊高度活躍在谷歌、三星、華為等各大手機廠商的致謝名單中,挖掘的漏洞屢次獲得CVE編號及致謝,在保證360產品安全的前提下,團隊不斷對外輸出安全技術,為移動互聯網安全貢獻一份力量。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 黑白之道 的精彩文章:

提權器Cobalt Strike發布3.6版本
iptables防火牆策略的配置
手機關機照樣被監控?如何知道自己手機是不是被監控了呢?
華盟 Web安全與滲透 第十三課 Php注入頁面與Php木馬的編寫 PPT及視頻下載
最新CVE-2017-8759漏洞復現的兩種姿勢

TAG:黑白之道 |