歡迎來到 黑吧安全網 聚焦網絡安全前沿資訊,精華內容,交流技術心得!

CVE-2019-8603(macOS漏洞):利用一個越界讀漏洞實現了Safari沙箱逃逸

來源:本站整理 作者:佚名 時間:2019-06-18 TAG: 我要投稿

在今年Pwn2Own中,有研究人員發現利用一個越界讀漏洞竟然實現了Safari沙箱逃逸,然后利用kextutil中存在的TOCTOU獲得內核代碼執行權限。
目前該漏洞已經被命名為CVE-2019-8603,簡單來說,這是一個存在于Dock和蘋果卸載網站(com.apple.uninstalld)中的堆越界讀取漏洞,該漏洞將導致攻擊者調用CFRelease并在macOS上實現Safari瀏覽器沙盒逃逸,最終獲取到目標設備的root權限。
另外,在測試過程中,CVE-2019-8606允許研究者通過kextutil中的競態條件(race condition),用root權限實現內核代碼執行。如果再借助一個qwertyoruiopz和bkth開發的WebKit引擎漏洞(遠程代碼執行漏洞),則研究人員可以完全實現Safari沙箱逃逸。
在本文發布時,該漏洞已經在最新的macOS 10.14.5版本中被修復了,所以本文我們可以對它的來龍去脈進行詳細復盤了。
詳細復盤
本來研究人員是計劃測試一個模糊測試工具的代碼覆蓋率,代碼覆蓋(Code coverage)是軟件測試中的一種度量,描述程式中源代碼被測試的比例和程度,所得比例稱為代碼覆蓋率。但測試到AXUnserializeCFType函數時,卻發現發現了CVE-2019-8603漏洞,這個函數是去年的Pwn2Own中發現的一個簡單解析器,不過當時并沒有發現其中有什么漏洞。不過在發現有漏洞后,研究人員對這個函數進行了仔細研究,發現它竟然是CoreFoundation對象序列化的另一種實現方式。Core Foundation框架(CoreFoundation.framework)是一組C語言接口,它們為iOS應用程序提供基本數據管理和服務功能。而AXUnserializeCFType則是HIServices框架的一部分,而且代碼就存儲在對應的dylib庫中。
可以通過此函數對CFAttributedString對象進行反序列化,CFAttributedString是一個字符串,其中每個字符與CFDictionary相關聯,CFDictionary包含了描述給定字符的任意屬性。這些屬性可以是顏色,字體或用戶關心的任何其他內容。而在本文的示例中,CFDictionary的屬性是代碼執行。
為了幫助大家更直觀地了解CFDictionary的屬性,研究人員專門列出了數據結構,數據結構使用游程長度(run-length)壓縮,而不是為每個單獨的字符專門分配字典:
// from CFAttributedString.c
struct __CFAttributedString {
    CFRuntimeBase base;
    CFStringRef string;
    CFRunArrayRef attributeArray;  //
例如,字符串“attribuis hard”可以在內部表示為3個CFRunArrayItems:
1.從索引0開始,長度11,“粗體”屬性標識;
2.從索引11開始,長度4,沒有屬性標識;
3.從索引15開始,長度4,“斜體”屬性標識。
顯然有一些不變量必須被維護,例如所有運行的union類型跨越整個字符串,并且沒有任何運行重疊。
反序列化函數cfAttributedStringUnserialize有兩個執行路徑,第一個路徑很簡單,它只讀取一個字符串,并為屬性dict調用帶有NULL的CFAttributedStringCreate。這意味著第二個路徑必須解析一個字符串,以及一個包含了范圍和關聯字典的列表,然后調用內部函數_CFAttributedStringCreateWithRuns:
CFAttributedStringRef _CFAttributedStringCreateWithRuns(
        CFAllocatorRef alloc,
        CFStringRef str,
        const CFDictionaryRef *attrDictionaries,
        const CFRange *runRanges,
        CFIndex numRuns) { ...
解析器將會確保運行的次數和字典的數量匹配,但是它不會對實際的字符串范圍信息執行任何驗證。同樣_CFAttributedStringCreateWithRuns也無法做到這一點。
    for (cnt = 0; cnt attributeArray, runRanges[cnt], attrs, runRanges[cnt].length);
 CFRelease(attrs);
    }
因此,研究者將能夠使用完全可控的range以及newLength值來調用CFRunArrayReplace。
void CFRunArrayReplace(CFRunArrayRef array, CFRange range, CFTypeRef newObject, CFIndex newLength) {
    CFRunArrayGuts *guts = array->guts;
    CFRange blockRange;
    CFIndex block, toBeDeleted, firstEmptyBlock, lastEmptyBlock;
    // [[ 1 ]]
    // ??? if (range.location + range.length > guts->length) BoundsError;
    if (range.length == 0) return;
    if (newLength == 0) newObject = NULL;
    // [...]
    /* This call also sets the cache to point to this block */
    // [[ 2 ]]
    block = blockForLocation(guts, range.location, &blockRange);
    guts->length -= range.length;
    /* Figure out how much to delete from this block */
    toBeDeleted = blockRange.length - (range.location - blockRange.location);
    if (toBeDeleted > range.length) toBeDeleted = range.length;
    /* Delete that count */
    // [[ 3 ]]
    if ((guts->list[block].length -= toBeDeleted) == 0) FREE(guts->list[block].obj);
    ...
仔細觀察上圖中的代碼段[[ 1 ]],很明顯,編寫這段代碼的人雖然對傳入的參數有所懷疑,但卻沒有更改函數簽名以返回錯誤信息。
而在代碼段[[2 ]]中,錯誤執行就開始了:如果range.location太大,那么blockForLocation就會返回一個越界索引。這意味著,代碼段[[ 3 ]]的FREE在調用CFRelease(使用越界索引獲取的指針來實現調用)時,漏洞就被觸發。

[1] [2]  下一頁

【聲明】:黑吧安全網(http://www.pcpbjo.tw)登載此文出于傳遞更多信息之目的,并不代表本站贊同其觀點和對其真實性負責,僅適于網絡安全技術愛好者學習研究使用,學習中請遵循國家相關法律法規。如有問題請聯系我們,聯系郵箱[email protected],我們會在最短的時間內進行處理。
  • 最新更新
    • 相關閱讀
      • 本類熱門
        • 最近下載
        云南快乐十分前三电视