1. 程式人生 > >CVE-2017-8890漏洞分析和利用-概覽篇

CVE-2017-8890漏洞分析和利用-概覽篇

本文永久連結:https://thinkycx.me/posts/2018-10-30-a-glance-at-CVE-2017-8890.html

最近在忙開題的事情,期間和同學聊了一下這個漏洞,想起來之前寫過一篇概覽的介紹,因此發出來給有需要的同學參考一下,後續可能還會再整理幾篇文章。這個漏洞是我除錯的第一個核心漏洞,2018上半年花了很多時間在這個漏洞的除錯和利用上面,從三月份開始斷斷續續除錯到八月初才結束,希望可以和對Kernel感興趣的同學一起交流。原文如下。

CVE-2017-8890是啟明星辰ADLab於2017年5月發現的linux核心中隱藏了11年的double free漏洞,影響了當時幾乎所有linux核心版本。在2018年初,國內安全媒體freebuf披露了該漏洞的利用細節,可以用於root 2017年5月之前幾乎所有的linux伺服器,並且可以在幾乎所有的Android手機上完成核心提權操作。由於漏洞型別是double free漏洞,因此僅有POC就可以完成核心的DoS,造成的危害和影響非常大。 在下面從漏洞原理、漏洞利用、漏洞防禦的角度來對該漏洞進行說明。

一、漏洞原理

linux 核心中的對該漏洞的補丁位於net/ipv4/inet_connection_sock.c中,使用inet_sk(newsk)->mc_list = NULL;來對mc_list成員初始化置null。newsk是一個sock的結構體指標(struct sock *newsk)。通過檢視原始碼,可知mc_list是ip_mc_socklist的結構體指標。通過對漏洞補丁函式inet_csk_clone_lock的呼叫鏈分析,可知該函式的功能是在建立三次握手時複製socket,但是由於沒有對socket中的ip_mc_socklist置null,導致了socket複製後在釋放時導致double free漏洞,從而核心發生崩潰。

由於是double free的漏洞,觸發漏洞時,必然要對mc_list進行建立和二次釋放。通過檢視核心原始碼中對mc_list所有引用,可知建立的呼叫鏈如下所示: 
圖1-1 mc_list建立過程

同理,mc_list釋放的過程如圖1-2所示。
 
圖1-2 mc_list釋放過程

明確了建立和釋放過程後,在POC中首先建立一個socket並加入組播模式(MCAST_JOIN_GROUP),這時socket中存在mc_list結構體。POC中監聽該socket並用accept等待連線。建立連線時,核心會建立子sokcet,其中存在父socket的mc_list結構體。關閉子socket,這時等待mc_list真正釋放後關閉父socket,可以同樣的位置觸發第二次free。這樣就可以觸發double free漏洞。POC的虛擬碼如表1-1所示。

sockfd = socket(AF_INET, …);
setsockopt(sockfd, SOL_IP, MCAST_JOIN_GROUP, …);
bind(sockfd,…);
listen(sockfd,…)
newsockfd = accept(sockfd,…);
close(newsockfd);  // first free
close(sockfd);     // double free

表1-1 觸發double free的POC

二、漏洞利用

漏洞利用的過程可以簡單分為這兩個過程:通過double free實現控制EIP,通過控制EIP來程式碼執行提升許可權。

觸發核心double free後,由於是double free的漏洞,兩次free的時機都可控。因此控制EIP的思路很簡單,在第一次釋放後,通過heap spray來佔位被釋放的obj,從而在第二次free的時候,嘗試利用佔位的資料去劫持EIP。

劫持EIP的主要難點有以下兩點:

  1. 堆噴射佔位obj
  2. 利用obj中的指標來劫持EIP

通過對ip_mc_socklist這個obj的原始碼分析可知,堆噴射的obj有如下要求:前八位元組可控、obj大於32byte小於等於64byte。

通過對於linux核心原始碼中sock_kmalloc這個堆噴射實現函式分析,可以得到類似如圖2-1的函式呼叫關係。

圖2-1 sock_kmalloc函式呼叫關係

對原始碼分析和測試後,找到了滿足條件的ip_mc_source這個函式,可以用於堆噴射。堆噴射控制EIP後,根據漏洞利用的環境不同,有對應不同的策略。

如在ubuntu上利用時,根據核心的保護措施不同,可以採取不同的利用思路。

  1. 沒有任何保護措施時,控制EIP後,直接跳轉到使用者態的shellcode即可完成root提權。
  2. 有SMEP時,核心態不能執行使用者態shellcode,可以通過核心rop結合shellcode來提權。
  3. 有SMAP時,核心態不能直接訪問使用者態資料,可以通過ret2dir把提權程式碼佈置在核心態完成root提權。

利用效果如圖2-2所示。

圖2-2 ubuntu root提權

如在Android手機上利用時,由於Android中採取的linux核心版本相對較低,通常為3.10,但大多開啟了PXN保護措施,核心態不能執行使用者態shellcode。因此通過控制PC指標後修改addr_limit,使用者態可以任意讀寫核心態。把double free轉化成核心態任意地址的讀寫後,修改當前程序的cred結構體提權到root。之後patch selinux這個核心保護措施,可以完成提權操作到init許可權(init許可權比root許可權更高)。

利用效果如圖2-3所示。

圖2-3 nexus6p Android手機提權

通過以上分析我們可以發現, POC的實現難度較低,造成的影響通常為DoS,會導致伺服器重啟、手機重啟。而提權root的難度較大,利用的實現過程比POC實現起來複雜很多,造成的危害也更大,可以導致伺服器和手機上資料被普通程式或APP竊取。

三、漏洞防範

為了在linux伺服器和Android手機上避免被非法程式或APP提權,開發者通常的防禦措施是更新核心版本。在各大linux發行版的更新文件中會指出當前更新會修復哪些漏洞,或者通過apt-get changelog的方式來檢視當前linux核心版本修復了哪些漏洞。如果熟悉linux核心原始碼,手工patch補丁後自己重新編譯核心也可以有效完成漏洞防禦。

由於該漏洞從產生到披露已經隱藏了11年之久,linux核心被眾多伺服器、IoT裝置使用,因此海量的裝置都遭受影響。對於國內的安全研究人員而言,提升對於linux核心的漏洞挖掘能力非常重要。但由於linux核心的原始碼達到了百萬的級別,採用人工審計的效率非常低下,因此採用一種高效的漏洞挖掘方法就非常必要。

通常漏洞挖掘中都會採用fuzz的方式來進行,通過分析fuzz出的crash來回溯分析crash的原因從而判斷是否可利用。該漏洞CVE-2017-8890的發現也是通過google的syzkaller fuzz框架發現的。因此,改進fuzz策略、改變fuzz的思路對於提升漏洞挖掘的效率會有非常大的幫助。漏洞挖掘後,判斷一個crash是否可利用,也會耗費大量的時間和精力,京東安全研究員在blackhat USA 2018中介紹了他們的linux 核心自動化漏洞利用框架FUZE,自動化的實現了部分linux核心的漏洞利用,大大縮短了漏洞利用的時間,幫助安全研究人員判斷漏洞是否可利用。

四、總結

該漏洞CVE-2017-8890從披露時就給行業內造成了巨大影響,幾乎所有基於linux核心的伺服器和Android手機都受影響。本文分析了該漏洞的原理,簡要介紹了ubuntu、Android手機上的利用過程和實現難度,最後對於linux核心漏洞的防範做了簡單的總結。

五、參考

  1. http://www.freebuf.com/articles/terminal/160041.html
  2. https://xz.aliyun.com/t/2383
  3. https://xz.aliyun.com/t/2385