CVE-2017-8890 深度分析

CVE-2017-8890 深度分析

0x00 說在前面的

筆者作為初入安卓內核漏洞利用分析的從業者,自 CVE-2017-8890 這個漏洞被曝之後不久就開始研究其成因、原理、觸發以及利用。至今遇到了無數問題,也解決了無數問題,於是記下這篇文章以做小結,一來對這段時間的工作學習做一個歸納總結,二來希望能對同樣對安卓內核漏洞感興趣的朋友有一些細節上的幫助。

0x01 原理分析

漏洞概述

+ 編號:CVE-2017-8890

+ 類型:double free

+ 位置:/net/ipv4/inet_connection_sock.c

+ 描述:

漏洞成因

分析一個漏洞的原理,最直接的方法是從補丁入手。

CVE-2017-8890 的補丁如下所示:

可以看到這個補丁非常簡單,只添加了一行代碼,作用是將 inet_sk(newsk)->mc_list 置為 NULL。再結合漏洞類型為 double free,很容易得知應該是釋放流程中對 mc_list 這個結構體的處理不當,導致了這個漏洞產生。那麼這裡比較關心的問題如下:

+ 這個對象是什麼?

+ 對象在哪裡產生?

+ 對象在哪裡釋放?

+ 為什麼會產生漏洞?

對象是什麼

通過源碼分析和搜索引擎可以知道,mc_list 這個對象代表的是組播列表。其原型如下:

既然這個結構體是組播列表,那麼很容易得知,當創建組播,加入組播的時候,很可能就會創建這個結構體。

對象在哪裡創建

通過前面的推測,加上內核源碼分析,能夠得出如下調用鏈,將會創建這個結構體。

用戶態:

setsockopt(MCAST_JOIN_GROUP)

內核態:

SyS_setsockopt() -> sock_common_setsockopt() -> ip_setsockopt() -> do_ip_setsockopt() -> ip_mc_join_group()

對象在哪裡釋放

知道了對象,創建流程,通過源碼分析也能夠找到釋放的調用鏈。

用戶態:

close(sockfd)

內核態:

sock_release() -> inet_release() -> tcp_close() -> ip_mc_drop_socket()

PS:這裡不得不說一下,我很佩服挖到這個漏洞的大佬,但是 【ADLab原創首發】「Phoenix Talon」in Linux Kernel —潛伏長達11年之久的內核漏洞 的兩次對象釋放寫在不同的位置很誤導人。

之所以能夠看到兩次不同的釋放,是因為 RCU 系統的存在,ip_mc_drop_socket 這個函數導致釋放操作,真正的釋放在 __rcu_reclaim。軟中斷是由於時鐘中斷導致,都是 RCU 釋放流程中的正常操作。兩次釋放都在同一個點,都是由於用戶態 close 導致的。

為什麼會產生漏洞

那麼問題的關鍵來了,為什麼會產生這個漏洞。

在搜集信息的過程中我們已經知道了這個漏洞是一個 double free,既然是 double free,那必然是一次創建,兩次釋放。但是從上面對象創建和釋放的流程來看,並不能找到兩次釋放的點。

這個時候,漏洞描述中的一句話給出了分析方向:

It turns out that leave a copy of parent mc_list at accept() time.

在 accept 的時候,子對象會從父對象複製一份 mc_list。

但如果是複製的話,對象應該也會複製一份,那麼對子對象和父對象都進行釋放,應該是不會產生漏洞的。帶著這樣的疑問對源碼進行了分析之後得到答案:

首先 mc_list 是 sock 對象的一個成員,並且是由 sock 中的指針所指向的對象

accept 的時候會把 sock 對象拷貝一份而不是 mc_list

由以上兩點就能夠解釋漏洞為何產生了 —— 多個對象擁有了指向同一個對象的指針。

那麼這個漏洞已經不是 double free 了,甚至可以是 X free,因為只要 accept 多次,那麼就會有多個對象指向同一個 mc_list。

漏洞觸發

從上面的分析中我們已經得到了幾個觸發漏洞的關鍵點:

+ 如何創建對象

+ 如何釋放對象

+ 為何產生漏洞

那麼 POC 的構建已經是輕而易舉了,偽代碼如下:

這裡需要注意的是 accept 要對應 connect。

0x02 利用分析

因為利用涉及到太多的技術細節,所以這裡主要講思路,具體還是要自己去調試分析才能知道明白,要知道,只有在調試器下,才是沒有秘密的。

思路分析

目前,我們擁有的條件如下:

+ 能夠觸發漏洞

+ 知道這個漏洞是 double free

目的如下:

+ 成功利用漏洞,達到任意地址讀寫

而漏洞利用就是在擁有的條件之下,不斷想方設法提升當前許可權,以達到最終目的的過程。

+ 創建漏洞結構體

+ 第一次釋放漏洞結構體

+ 通過堆噴覆蓋對漏洞結構體進行佔位

+ 在用戶空間中去使用已經 free 掉的對象,嘗試通過某種方式獲得在內核中執行代碼的能力

那麼這裡比較關鍵的問題就是如何進行佔位,以及如何在用戶態通過這個漏洞獲得在內核中執行代碼的能力。

堆噴佔位

堆噴這個手法,說得直白一點,就是不斷地申請內存,由於 linux 的 slab 分配機制會把大小相同的塊分配在一起,所以當操作量足夠大的時候,隨機分配的堆也會逐漸變得可以預測。

從 IDA 中可以得知測試機(Nexus 6P)中的 mc_list 大小為 0x30,那麼堆噴的時候只要不斷地申請大小為 0x30 的結構體即可。

這裡我所用的對象是 ipv6 的 mc_list(一開始使用的方法是 sendmsg,不過這個方法由於內核的釋放機制而相當不穩定),首先這個對象大小在測試機上是 0x30,其次因為一些關鍵的特性,讓這個結構體成為非常理想的堆噴對象。

劫持 EIP

前面提到當我們成功進行了佔位之後,需要通過某種方式來獲得在內核中執行代碼的能力,及劫持 EIP。通常我們的做法是用我們的地址去覆蓋某個函數指針,然後觸發這個指針,這樣內核就會把這個地址當成對應的函數去解析,從而達到劫持 EIP 的目的。就可以直接執行 shellcode 了(當然 64 位機存在 pxn 所以需要通過 jop 來繞過)

這裡深入分析 mc_list 這個結構體可以看到:

這個結構體的最後一個成員是一個函數指針,那麼這個函數會在什麼情況下被使用呢?

答案是在 kree_rcu 的釋放流程中。

從前面的分析可以看到,最終釋放 mc_list 的位置是 __rcu_reclaim,這個函數實現如下所示:

這個函數中首先對 head->func 進行了檢測,如果小於 4096,則把這個作為一個便宜,將其釋放掉,如果大於 4096,則當成一個函數地址來執行。

那麼利用思路就比較清晰了:

+ 第一次釋放

+ 覆蓋,重點覆蓋 head->func

+ 第二次釋放,觸發 head->func

通過這樣的方式的確能夠劫持 EIP,不過在實際的利用過程中,存在一個問題:在 64 位機上存在 PXN 防護,需要通過 jop 的方式來繞過這個防護機制,而 jop 需要能夠控制至少一個寄存器,但 rcu_head 中的 next 是作為一個地址傳過來的,並不能通過寄存器控制,所以在 64 位機上並不能直接通過這種方式完全利用達到提權的目的。

分析到這裡的時候,思路一度陷入了僵局,最後從下面這篇文章中得到了解決思路:

CVE-2017-8890漏洞分析與利用(Root Android 7.x)

文中提出的思路如下:

+ mc_list 在內核中以鏈表形式存在,通過第一個成員指向下一個 mc_list

+ 當要釋放一個 mc_list 的時候,rcu_head 會被鏈到一個釋放鏈表中

+ 我們可以在用戶態偽造一個 fake_mc_list,讓被堆噴的對象的 next_rcu 指向用戶態的fake_mc_list

+ 通過判斷 fake_mc_list.rcu-next 是否為空來確定是否成功的讓 fake_mc_list 上鏈

通過上面的信息可以知道,我們堆噴的對象的前 8 位一定要是可控的,前面提到的 ipv6 的 mc_list 剛好滿足這個條件。那麼最終的利用思路如下:

+ 用戶態創建結構 fake_mc_list

+ mmap(fake_mc_list)

+ 創建漏洞結構體

+ 第一次釋放

+ 堆噴

+ 第二次釋放,使 fake_mc_list 上鏈

+ fake_mc_list .rcu->func 為 JOP 地址

0x03 PXN 繞過

pxn 的繞過手法通常是 jop,這其實更算是體力活,所以不詳述思路。

我們想要通過 jop 完成某樣功能,那麼就要先構思一條理想中的 jop,然後仿照這條 jop 在彙編中進行查找,通過正則的方式會比較高效。

舉個例子,如果我們想要 patch 一個內核函數地址,假設為 ptmx_ioctl,當前可控寄存器為 x1,那麼理想中的 jop 代碼應該如下所示:

0x04 參考

  • 【ADLab原創首發】「Phoenix Talon」in Linux Kernel —潛伏長達11年之久的內核漏洞
  • CVE 2017 8890內幕
  • CVE-2017-8890漏洞分析與利用(Root Android 7.x)
  • 如果有什麼需要交流的,可以聯繫 Yearthmain@outlook.com

原文鏈接:[原創]CVE-2017-8890 深度分析

本文由看雪論壇 Yearthmain 原創,轉載請註明來自看雪社區


推薦閱讀:

iPhone8更新iOS11.3後部分用戶屏幕觸摸反饋無法正常使用
大霧制約通航,瓊州海峽跨海大橋為何卻遲遲不建?
《戰狼2》中的無人機太逆天,帶你看看九寨地震中的無人機牛操作!
OneWay李維:短視頻和VR廣告在2017年的發展
在高解析度資源缺乏的情況下,目前購買 4K 電視意義大嗎?

TAG:科技 | 安全漏洞 | Android |