安卓內核UAF漏洞利用探秘

雷鋒網編者按:8月16日,第三屆中國互聯網安全領袖峰會(CSS 2017)在北京國家會議中心召開。作為九大分會場之一的騰訊安全探索論壇(TSec)以「安全新探索」為主題,雲集了國際知名廠商及頂尖高校的資深安全專家,探討全球信息安全領域前沿技術、研究成果及未來趨勢。來自騰訊安全科恩實驗室的方家弘、申迪分享了面對安卓內核中存在的UAF漏洞數量不斷變小、利用難度逐漸變大的現狀,將如何穩定高效地利用這類漏洞來完成操作系統提權。

方家弘:大家下午好!我是來自騰訊安全科恩實驗室的方家弘,我和我的同事申迪給大家帶來關於「安卓內核 UAF 漏洞利用探秘」的分享。

今天的分享主要分成四個部分。首先由我介紹在之前的一段時間出現的比較有代表性的安卓內核漏洞。其次要分析像 UAF 這樣一個特定類型的漏洞在利用方面有什麼樣的特點,它涉及到系統組件的基礎知識,方便大家理解後續的內容。之後的時間交給申迪,他會具體分析在 perf 子系統中發現的 UAF 漏洞的具體利用過程。最後,分享一點我們的總結和思考。

首先介紹安卓內核漏洞的簡要歷史。

為什麼要對安卓內核進行攻擊呢?

將安卓系統看做整體,最早系統中以不同的應用,使用不同的 UID ,對應用之間進行隔離。後來發現這並不能阻擋攻擊,又產生了加密文件系統等等安全措施。

而絕大多數措施的實現都依賴於安卓的內核。攻擊內核本身是非常有助益的工作。在 Windows 系統當中,攻擊內核可以直截了當的達到提權的目的。在安卓系統中,也可以繞過系統中設置的種種限制。對於壞人可以實現他不可告人的目的。

按照時間軸,根據我個人的理解列出了比較有代表性的內核漏洞。當然,不包括我們今天要講的漏洞。

2013 年 11 月份,CVE-2013-6282 是我們的友商寫出的最早的漏洞,它是邏輯問題。在我們去年攻擊特斯拉的時候,驚訝地發現這個漏洞居然還存在。當時特斯拉比較自信的認為車輛不可能被攻破,所以他們在內核方面沒有做更多的防禦。在漏洞被報告,修復之後,特斯拉在內核方面做了非常激進的更新和修復。加粗的漏洞都屬於通用的安卓 root 漏洞。

2014 年,美國的兩個天才少年發現了 towelroot,這是引起比較大反響的通用 root。這個漏洞類型在當時較新穎,這個漏洞的利用方式也非常創新,引起了不小的波瀾。

2015 年 5 月份,我們發現了 CVE-2015-3636。

2016年8月份,我們利用了 CVE-2015-1805。

之後就是非常出名的 Dirty COW,它也是屬於邏輯的問題。

2017年4月份,由 Google 研究員發現的 wifi Firmware 的漏洞,這是非常有創新特色的漏洞利用。

之前提到的是幾個有代表性的漏洞,6282 屬於業務邏輯的問題;1805 是屬於越界訪問;3153、3636 都屬於 UAF 漏洞。今天我們主要針對 UAF 漏洞進行研究和探討。

顧名思義,UAF 漏洞先要 after Free,而要成功利用這個漏洞,有幾個步驟是不能少掉的。一是如何按照順序去觸發 free 和 use。這看似比較簡單,以 2015-3636 為例,use 的時機和 free 的時機非常可控,我們可以做任意想做的事情,比較好控制被 free 掉的空間。

3636 這個漏洞的品相非常好,但在很多情況下的控制環節上,可能會面臨競態的問題。在這種情況下,如何穩定的控制好 free 和 use 的順序,並且穩定的觸發 use,就是比較困難的問題。對於不同的漏洞來講,需要不同的技巧去處理。我們已經能夠把時序上的問題清楚,之後就是如何改變內核的控制力,如何控制代碼執行。控制出來被 free 的空間方法,不同的漏洞,有不同的方法。

這裡牽涉到最重要的就是 Linux 內核的內存管理。我們以圖示的形式展示了 UAF 漏洞利用的方式。堆上有 ABCD 四個對象。這是一個比較簡單的呈現方式,要做到能夠穩定有效的 free 掉目標對象,並且把我們想要的東西填進去,需要對內核存儲管理有比較深入的了解,也就牽涉到 Linux 內核的堆管理器。

在安卓系統當中,我們對常見的堆管理器叫 SLUB,它替換了之前常見的 SLAB。從管理結構上來講,SLUB 是簡化版的,U 就是 unqueued 的意思。queued 是隊列,做堆管理器,總要有隊列,申請的時候從這裡拿。它取消了單獨存在隊列的結構,這樣就使得完全空閑的 SLUB 被完全釋放掉。它存在 per cpu 的 slab,它的釋放和申請的過程會非常快。為了實現兼容性,Linux 的管理是抽象到 kmem 層。之前的內核代碼、內核驅動,不需要做任何的修改。如果大家自己編譯過 Linux 內核,只需要選擇什麼樣的堆管理器就可以直接使用,其它代碼都不用更改。


首先看一下 SLUB 的堆塊長什麼樣子。Linux 內核當中物理內存的頁面管理是通過 buddy 進行的。要符合物理頁面管理的原則。在 SLUB 當中,都是二的 N 次方組成頁組成的。它實際上是巧妙的利用了物理頁面描述服的聯合,實現了管理。我分配好給這個堆塊的這些頁,第一個頁面的描述符上就會記錄堆塊中可使用的第一個對象。這就是空閑對象列表的頭部。在空閑對象的頭部,又會有一個指針,指到下一個空閑對象。

這個東西沒有額外的元數據,所有的元數據只存在於原有的結構體當中,存在於你分配給這個堆塊的頁面當中。這也帶來了一些特性,使得它可以幫助我們對特定的漏洞進行利用。

前面提到了 cpu_slub 的概念,分配和釋放都是快速的過程。當前分配的對象在於 cpu 綁定 slub 上面,就會進入快速分配的流程。不管怎麼樣,對於使用堆管理器的用戶來講,肯定會得到空閑的 slub 對象供使用。具體怎麼操作,就由 slub 的堆管理器進行。


為什麼要設定 cpu_slub,大部分情況下在一個調度周期內會有頻繁的對象分配操作。釋放也是這樣的情況,目前的對象就是隸屬於當前的 cpu_slub,這就帶來了另外一個非常好的特性。當前 cpu 上釋放的對象,我馬上要申請的,肯定申請到剛剛釋放的對象,這對於填充是非常好的特性。這個特性在其它的漏洞利用當中也會使用到。同時,釋放也存在 slow path,這是不可避免的情況。


這裡對 SLUB 的特性進行了歸納。按照對象的大小會做一個合併,這會對漏洞利用帶來一些問題,你可能不知道這樣的堆塊當中放的還有其他什麼對象。

接下來看兩個漏洞的案例,這兩個案例充分利用了 slub 堆管理器的特性。

首先是 CVE-2015-1805。

iovec 是數據內核中傳遞數據的結構。這個漏洞本身是 overrun,牽涉到我們在內核當中如何申請可控的overrun 數組。在安卓當中,很多 API 是被禁用的。最終我們找到 sendmmsg 的調用,你可以得到內容完全可控的數組。它的壞處是放完以後就被銷毀掉了。

這個對象本身的生命周期不夠長。看似這不是很好的對象,實際上可以回想起之前的一點,在 slub 中一個對象被釋放之後,僅僅是在對象的頭部寫入了指針,這個指針指向下一個可以使用的對象。

2015-1805 的代碼路徑當中,如果 iov 是 0,根本就不會被處理。如果說噴射的夠快,漏洞利用過程夠快,被釋放掉的 iov 本身還是空的對象,或者又被另一個 iov 填上,根本不會對漏洞造成任何影響。我們只需要控制填進去的第一個 iov 的長度是 0,它就會被忽略掉。即便被釋放,這個結果還是有效的 iov。

第二個漏洞,應該是 2016-6187。通過這個方法,把一個品相非常差的漏洞,越界寫一個字符節的 0,變成可能導致代碼執行的情況。最後也是通過 freelist 指針的特性。

接下來的時間交給申迪,由他分析一下在 perf 子系統中發現的漏洞利用。

申迪:下面給大家介紹我在去年發現的兩個 perf 系統的 UAF。在安卓手機上有很多用戶有一鍵 root 的需求。一些 UAF 漏洞的品相併不是特別好,但我至少要寫到達到 90% 的成功率。我主要介紹兩個在去年年初發現,年底報給 Google 的漏洞。

第一個是 CVE-2016-6787,它是通過 Race觸發的漏洞,內核立即崩潰。上周我在 BlackHat 講了繞過三星 KNOX 的防護機制。

第二個漏洞是 CVE-2017-0403,這是今年才修復的漏洞。這個漏洞有它自己的難點。

在講漏洞之前,先講一下 perf 是什麼東西,它是系統調用,任何安卓都可以調這個系統調用,攻擊內核。這個系統調用有很多問題,我也發現不止兩個問題,這邊兩個是比較好利用的,單獨拿出來講一下。這個系統調用的參數比較複雜,其中一個是你怎麼定義你想生成的統計事件,你想定義代碼執行的指定周期,或者是真正調用進入內核的時候又調用了哪些調用,它包含了千奇百怪的 perf 事件,可能會進入到分支。

這個系統調用,不管中間發生了什麼,最後總會生成 perf_event。每個都不是孤立的,有可能是一組形式出現的,每個 groun 都有一個 leader,每個進程里有多個組,又有大的容器包括這個組。每個進程里有兩個 perf_event_context,把作為的 group leader 串聯起來,這 list 把組內的串聯起來,這三個內核對象有一個比較複雜的連接的關係,其實就是因為這些關係搞得很複雜,系統調用里出了一些 UAF 的問題。

Googl 在 2016 年下半年覺得這個系統調用太危險,直接封掉了。去年年初,這個調用還可以被其它的調用調到,我利用這兩個漏洞完成了手機上的 root。

第一個漏洞的問題主要是由於系統調用里的 move_group。


如果 group leader 是軟件的,你要插入一個硬件的,這個時候會挪動大量列表相連的關係。首先會把 group leader 從指針上提取出來,把每個 event 粘出來。這兩個操作完成之後,又看到紅框里的代碼,減了 1,這個減 1 沒有考慮到併發操作,把一個組摘除了兩遍。正常情況下,只減 1,併發操作就要減 2,被多減了一個,引用減到 0,導致觸發釋放。

主線程先創建一個 group leader,線程 1 觸發 move_group操作。右邊出現了崩潰,實際是因為 perf_event context 被提前釋放。你的進程在第二次進入調度的時候,進入調度器會調入一行,周期執行完了會換出,換出之後再被進程調度器換入。

這個時候就會觸發操作。關鍵是線程調度是很頻繁的,基本不是肉眼可觀測的。漏洞一旦觸發,內核立即就崩潰了。實際上它不是立即崩潰,實際上有一個微笑的操作,線程已經被換出,換入的時候又崩潰了。假如是一個立即的崩潰,對我來說就是毫無意義。這個時候就要集中解決一個問題,怎麼讓內核不立即崩潰,給我爭取到足夠的時間去噴堆。

在講這個問題之前,要先講一下 Linux 內核的調度知識,包括很多線程,每個線程不可能同時執行。真正執行的是一個,其它都是等待執行。它執行一段時間之後,會有幾種情況。有一種情況就是以後再也不需要執行,它就會被殺掉。如果該想繼續執行,配合的時間片已經被用盡了,這個時候就被線程調度器切換出去。這種時候就會進入到 interruptible 或者是 uninterruptible。

futex 這個調用可以幫助我們完成真正的睡眠。一旦線程進入睡眠的狀態,是不會被任何人主動喚醒。這對我們來說是最理想的狀態。

有了這個函數的幫助,整個調用邏輯就變成這樣的,從左到右,從觸發漏洞,到噴堆、代碼執行控制完整的流程圖。還是主線程創建 group leader,直接調 queue_me。線程1和線程2都同時觸發 perf_event 的工作。調了 queue_me 之後,三個線程全部睡眠掉了。這個時候我需要再建另外一個新進程,幫助我完成噴堆。噴堆並不是很難,1024 的對象,你直接噴堆,直接噴物理頁面,也是可以的。可能需要十幾秒的時間,把堆噴滿。這個時候我可以喚醒進程,或者直接殺掉進程,這都無所謂。線程調度器會調 sched_in。disable 可以指向你想控制的任何一個地址。你可以執行內核任意代碼,把權限提到 root。

另外一個 2017-0403 漏洞。最後一條是被釋放的對象,每個方塊都可以代表 0X10 的位元組,它沒有任何指針,你怎麼控制 PC 做代碼執行呢?

free 之後你能鎖 use 的部分就是紅色的兩個框,是 0X10 的單位,可以寫兩個指針的地址。A 是對象地址本身,第二個是 A+0X20 的位置。你可以用內核的其它對象去噴對,在 0X20 這個位置正好有一個 buffer,把它的地址覆蓋成 A 地址本身,你真正寫的是地址 A 本身,通過覆蓋地址 A 本身的方法把 UAF寫成堆溢出,再覆蓋其它對象,這個時候就比較好寫。如果不能控制 PC 指針,UAF 並不好寫。

總結

演講后,科恩實驗室在接受雷鋒網採訪時提到,Google 是非常重視安全的公司,在他們每月發的安全公告裡面有很多安全漏洞,但絕大部分安全漏洞的利用場景非常困難,甚至是無法利用的,而其中真正威脅用戶手機的漏洞是比較少的。

智能手機剛剛興起時,眾人對安全問題考慮不多。而隨着攻擊途徑和攻擊方向的增加,安全問題會被越來越重視。越來越多的人用新的方法去挖掘漏洞,其數量會變得越來越少。一旦發現新的攻擊方法、新的漏洞模式,可能就會有一波漏洞攻擊方法被爆發出來。隨着慢慢被重視,攻擊路徑被堵住。

因此,面對越來越健壯的 Android 內核,攻擊面急劇縮緊,只剩下一部分系統調用可供攻擊。在這其中,品相好的漏洞相對於品相不好的漏洞並不多。

但科恩實驗室的方家弘告訴雷鋒網,一般來說只要是漏洞都需要被修補,事實上品相好的漏洞通常會更快修補,因為被利用的危險更大。這就是為什麼優秀的安全研究團隊,比如 project zero,常常輸出「高質量」的漏洞,也就是能夠輸出漏洞和利用思路甚至是完整的利用代碼。漏洞的品相好壞有時候也很難判斷,除非寫出具體的利用代碼。

當然,這個其實不是安卓的特例。漏洞和很多東西一樣,比如玉石原石類,都有一個「品相」。漏洞的品相取決於很多因素,比如漏洞所在的攻擊面是否容易訪問到、漏洞的觸發是否容易和穩定,等等。所以有無法利用的漏洞是很正常的。

申迪也總結了面對無法利用的漏洞做法,首先要確定核心問題到底是什麼,是不是真的不能利用,還是有其它辦法。也可以藉助內核中的其它特性,或者參考過往的案例,畢竟有些思想是共通的,可以幫助你有些想法。

即使最後真的發現無解,也可以丟開一段時間。他回憶起自己寫 2014-0403 那個漏洞,也是丟開了 1、2個月,突然想到一個方法寫出來的。

最後,不要盲目報告一些無法利用漏洞,沒有人覺得你真的厲害。


想在手機閱讀更多css資訊?下載【香港矽谷】Android應用
分享到Facebook
技術平台: Nasthon Systems