國外大神Kevin Backhouse剛剛放出了一篇博文,對蘋果操作系統內核中發現的堆緩沖區溢出漏洞(CVE-2018-4407)進行了一番解構。
該漏洞使得攻擊者只要接入同一Wi-Fi網絡,即可向其他毫不知情的用戶發送惡意數據包來觸發任何Mac或iOS設備的崩潰和重啟。由于該漏洞存在于系統網絡核心代碼,因此任何反病毒軟件均無法防御。
運行以下操作系統的設備易受攻擊:
Apple iOS 11及更早版本:所有設備(升級到iOS 12的部分設備)
Apple macOS High Sierra(受影響的最高版本為10.13.6):所有設備(通過安全更新2018-001修復)
Apple macOS Sierra(受影響的最高版本為10.12.6):所有設備(通過安全更新2018-005中修復)
Apple OS X El Capitan及更早版本:所有設備
好在Kevin在發現這個漏洞后馬上就向蘋果報告了,蘋果在10月30日推出的iOS 12.1更新包中徹底修復了這個漏洞。
概述
該漏洞是蘋果XNU操作系統內核中網絡代碼的堆緩沖區溢出問題導致的,iOS和macOS都使用XNU,因此iPhone、iPad和的MacBook均受到影響。想要觸發該漏洞,攻擊者只需要連接到與目標設備相同的網絡,發送惡意IP數據到目標設備的IP地址即可,無需誘騙用戶進行任何交互操作。
舉個例子:
用戶在咖啡館使用免費Wi-Fi時,攻擊者可以加入相同的無線網絡并向用戶的設備發送惡意數據包就可以讓設備崩潰和重啟。(攻擊者只要使用NMAP工具就能很方便地獲得設備IP地址。)
由于該漏洞的成因來源于系統的核心代碼,反病毒軟件也無法防御。 Kevin在運行McAfee ® Endpoint Security for Mac的Mac上成功測試了該漏洞。這和用戶在設備上運行的軟件也沒有關系,即使沒有打開任何端口,惡意數據包仍會觸發漏洞。
進一步推測的話,由于攻擊者可以控制堆緩沖區溢出的大小和內容,因此他們可能利用此漏洞在目標設備執行遠程代碼。
緩解措施
在未升級到最新版本操作系統的設備上,目前已知的緩解措施只有以下兩個:
在macOS防火墻中啟用隱藏模式可防止攻擊。這個系統設置默認情況下不啟用,需要用戶手動開啟。iOS設備不支持隱藏模式。
不接入公共無線網絡。觸發該漏洞的唯一必要條件是處于同一Wi-Fi網絡,該漏洞不支持通過互聯網發送惡意數據包而觸發,Kevin測試過了。
漏洞分析
該漏洞來源于代碼中的緩沖區溢出(bsd/netinet/ip_icmp.c:339):
m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
函數icmp_error使用該代碼,目的是“生成包含錯誤信息的數據包以響應發生錯誤的IP”。它使用ICMP協議發送錯誤消息,引發錯誤的數據報頭包含在ICMP消息中,上述第339行代碼調用m_copydata的目的是復制錯誤數據包的報頭到ICMP消息。
問題在于報頭對于目標緩沖區來說可能太大了。目標緩沖區是mbuf,mbuf是一種數據類型,用于存儲傳入和傳出的網絡數據包。在此代碼中,n是一個傳入的數據包(包含不受信任的數據),而m是傳出的ICMP數據包。我們可以看到,icp是指向m的指針。m在第294行或第296行進行部署:
if (MHLEN > (sizeof(struct ip) + ICMP_MINLEN + icmplen))
m = m_gethdr(M_DONTWAIT, MT_HEADER); /* MAC-OK */
else
m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
往下看第314行,mtod用于獲取m的數據指針:
icp = mtod(m, struct icmp *);
mtod僅僅是個宏,因此這行代碼不會檢查mbuf是否足以容納icmp結構。此外,數據沒有復制到icp,而是復制到&icp->icmp_ip,存在+8字節偏移。
由于沒有必要的工具,Kevin無法在調試器中單步執行XNU內核,因此對于mbuf的分配大小沒有確切的數值。基于源代碼提供的信息,這里推測m_gethdr創建一個mbuf可以容納88個字節,m_getcl無法確定。但是根據實驗結果,觸發該緩沖區溢出漏洞時滿足icmplen >= 84的條件即可。
漏洞的發現過程
使用QL查找漏洞
Kevin是在分析數據包管理程序緩沖區溢出漏洞時發現的該漏洞。漏洞是由對于mbuf_copydata的調用(包含用戶控制的大小參數)引起的,因此只要寫一個簡單的查詢腳本即可發現類似錯誤:
**
* @name mbuf copydata with tainted size
* @description Calling m_copydata with an untrusted size argument
* could cause a buffer overflow.
* @kind path-problem
* @problem.severity warning
* @id apple-xnu/cpp/mbuf-copydata-with-tainted-size
*/
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph
class Config extends TaintTracking::Configuration {
Config() { this = "tcphdr_flow" }
override predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "m_mtod"
}
override predicate isSink(DataFlow::Node sink) {
exists (FunctionCall call
| call.getArgument(2) = sink.asExpr() and
call.getTarget().getName().matches("%copydata"))
}
}
from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "m_copydata with tainted size."
這是一個很簡單的問題跟蹤方法,它的查找范圍涵蓋m_mtod到CopyData函數的參數大小的數據流。m_mtod函數返回一個mbuf的數據指針,它很可能會返回不受信任的數據,所以mtod宏指令是根源所在。而m_mtod這只是XNU內核中不受信任數據的眾多來源之一。
|