安天移动安全发布“大脏牛”漏洞分析报告(CVE-2017-1000405)
一、背景簡介
臟牛漏洞(CVE-2016–5195)是公開后影響范圍最廣和最深的漏洞之一,這十年來的每一個Linux版本,包括Android、桌面版和服務器版都受到其影響。惡意攻擊者通過該漏洞可以輕易地繞過常用的漏洞防御方法,對幾百萬的用戶進行攻擊。盡管已針對該漏洞進行了補丁修復,但國外安全公司Bindecy對該補丁和內容做出深入研究后發現,臟牛漏洞的修復補丁仍存在缺陷,由此產生了“大臟?!甭┒础;诙嗄暌詠磲槍σ苿佣寺┒吹募夹g積累和安全對抗,安天移動安全對“大臟?!甭┒催M行了詳細的技術分析,并提供了驗證方案,全文如下。
二、漏洞原理分析
2.1 臟牛漏洞回顧
在分析大臟牛漏洞前,我們需要對原始的臟牛漏洞利用方式進行完整的分析理解: 之前的漏洞是在get_user_pages函數中,這個函數能夠獲取用戶進程調用的虛擬地址之后的物理地址,調用者需要聲明它想要執行的具體操作(例如寫/鎖等操作),所以內存管理可以準備相對應的內存頁。具體來說,也就是當進行寫入私有映射的內存頁時,會經過一個COW(寫時拷貝)的過程,即復制只讀頁生成一個帶有寫權限的新頁,原始頁可能是私有保護不可寫的,但它可以被其他進程映射使用。用戶也可以在COW后的新頁中修改內容之后重新寫入到磁盤中。
現在我們來具體看下get_user_pages函數的相關代碼:
整個while循環的目的是獲取請求頁隊列中的每個頁,反復操作直到滿足構建所有內存映射的需求,這也是retry標簽的作用。
follow_page_mask讀取頁表來獲取指定地址的物理頁(同時通過PTE允許)或獲取不滿足需求的請求內容。在follow_page_mask操作中會獲取PTE的spinlock,用來保護試圖獲取內容的物理頁不會被釋放掉。
faultin_page函數申請內存管理的權限(同樣有PTE的spinlock保護)來處理目標地址中的錯誤信息。在成功調用faultin_page后,鎖會自動釋放,從而保證follow_page_mask能夠成功進行下一次嘗試,以下是涉及到的代碼。
原始的漏洞代碼在faultin_page底部:
上面這個判斷語句想要表示的是,如果當前VMA中的標志顯示當前頁不可寫,但是用戶又執行了頁的寫操作,那么內核會執行COW操作,并且在處理中會有VM_FAULT_WRITE標志。換句話說在執行了COW操作后,上面的if判斷為真,這時就移除了FOLL_WRITE標志。
一般情況下在COW操作后移除FOLL_WRITE標志是沒有問題的,因為這時VMA指向的頁是剛經過寫時拷貝復制的新頁,我們是有寫權限的,后續不進行寫權限檢查并不會有問題。 但是,考慮這樣一種情況,如果在這個時候用戶通過madvise(MADV_DONTNEED)將剛剛申請的新頁丟棄掉,那這時本來在faultin_page后應該成功的follow_page_mask會再次失敗,又會進入faultin_page的邏輯,但是這個時候已經沒有FOLL_WRITE的權限檢查了,只會檢查可讀性。這時內核就會將只讀頁面直接映射到我們的進程空間里,這時VMA指向的頁不再是通過COW獲得的頁,而是文件的原始頁,這就獲得了任意寫文件的能力。
基本來看,上述的過程流也就是臟牛漏洞的利用過程。
在faultin_page中有對應的修復補丁:
同時也加入了另一個新的follow_page_mask函數:
與減少權限請求數不同,get_user_pages現在記住了經過COW循環的過程。之后只需要有FOLL_FORCE和FOLL_COW標志聲明過且PTE標記為污染,就可以獲取只讀頁的寫入操作。
2.2 大臟牛漏洞分析
THP通過PMD(Pages Medium目錄,PTE文件下一級)的_PAGE_PSE設置來打開,PMD指向一個2MB的內存頁而非PTEs目錄。PMDs在每一次掃描到頁表時都會通過pmd_trans_huge函數進行檢查,所以我們可以通過觀察PMD指向pfn還是PTEs目錄來判斷是否可以聚合。在一些結構中,大PUDs(上一級目錄)同樣存在,這會導致產生1GB的頁。 仔細查看臟牛補丁中關于THP的部分,我們可以發現大PMDs中用了和can_follow_write_pte同樣的邏輯,其添加的對應函數can_follow_write_pmd:
然而在大PMD中,一個頁可以通過touch_pmd函數,無需COW循環就標記為dirty:
這個函數在每次get_user_pages調用follow_page_mask試圖訪問大頁面時被調用,很明顯這個注釋有問題,而現在dirty bit并非無意義的,尤其是在使用get_user_pages來讀取大頁時,這個頁會無需經過COW循環而標記為dirty,使得can_follow_write_pmd的邏輯發生錯誤。
在此時, 如何利用該漏洞就很明顯了,我們可以使用類似臟牛的方法。這次在我們丟棄復制的內存頁后,必須觸發兩次page fault,第一次創建它,第二次寫入dirty bit。
調用鏈:
經過這個過程可以獲得一個標記為臟的頁面,并且是未COW的,剩下的就是要獲取FOLL_FORCE和FOLL_COW標志了。這個過程可以采取類似dirtyCOW的利用方式。
總結這個漏洞利用的思路如下:
1.首先經過COW循環,獲取到FOLL_COW標志
2.用madvise干掉臟頁
3.再次獲取頁將直接標記為臟
4.寫入
三、影響范圍
3.1 漏洞影響范圍
由于從2.6.38內核后才開始支持THP,所以漏洞影響所有內核在2.6.38以上并且開啟THP的Linux系統。萬幸的是在大多數Android系統的內核中沒有開啟THP,所以對于Android系統幾乎沒有影響。
3.2 如何在系統上查看是否受到影響
如果是開發者,有內核源碼可以查看編譯的config文件,看CONFIG_TRANSPARENT_HUGEPAGE是否打開
如果沒有源碼,在shell中可以查看/sys/kernel/mm/transparent_hugepage/enabled,如果輸出結果為[always]表示透明大頁被啟用、[never]表示透明大頁被禁用、[madvise]表示只在MADV_HUGEPAGE標志的VMA中啟用THP,例如:
如果以上兩者都沒有,可以查看/proc/meminfo,如果連HugePage*都沒有,那就說明沒有開啟大頁面,也不會受到漏洞影響。
四、驗證代碼
驗證POC請參照:https://github.com/bindecy/HugeDirtyCowPOC
五、修復建議
截止到文章發布時間,Linux各發行版本還未公布針對該漏洞的補丁信息,軟件開發人員可通過:https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?h=linux-4.9.y&id=7031ae2ab37d3df53c4a4e9903329a5d38c745ec重新編譯Linux修復該漏洞。如果開發人員暫時無法編譯和替換內核,可以通過關閉透明大頁(THP)來緩解。
六、總結
“臟牛”漏洞是Linux內核之父Linus親自修復的,他提交的補丁單獨針對“臟牛”而言并沒有問題。從我們的分析過程中發現,內核的開發者希望將“臟?!钡男迯头椒ㄒ玫絇MD的邏輯中,但是由于PMD的邏輯和PTE并不完全一致才最終導致了“大臟?!甭┒?。連內核的開發者都會犯錯,更何況普通的開發者。
“大臟牛”漏洞再一次提示我們,即便是官方修復過的漏洞仍有可能由修復補丁引入新的嚴重漏洞,漏洞在修復后需要我們像對待原始漏洞一樣繼續跟蹤其修復補丁。
七、參考資料
1.https://medium.com/bindecy/huge-dirty-cow-cve-2017-1000405-110eca132de0 2.https://bbs.pediy.com/thread-223056.htm 3.https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1000405
轉載請注明來源:http://blog.avlsec.com/?p=4961
總結
以上是生活随笔為你收集整理的安天移动安全发布“大脏牛”漏洞分析报告(CVE-2017-1000405)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安天移动安全:Janus高危漏洞深度分析
- 下一篇: 真假应用傻傻分不清,HideIcon病毒