Linux 內核 waitid 系統調用本地提權漏洞(CVE-2017-5123)的分析與利用
發布時間:2017-11-01  信息來源:任子行

最近在整理Linux內核漏洞利用的一些場景,比如利用系統調用漏洞、利用一些比較容易fuzz的漏洞,通過對這類場景的總結可以幫助我們快速發現0day,積累漏洞挖掘的經驗。雖然這一類型的漏洞出現的頻率很低但是優點也很顯著,這類漏洞利用比較簡單、直接。我通過查看githubLinux源代碼patch日志發現CVE-2017-5123就是我要收集的目標,這類漏洞的攻擊面是內核處理用戶態指針出錯,一般是內核沒有檢查用戶態指針就直接使用,或者是對用戶態指針檢查不正確(本來是用來read的指針,卻用來write, 一般會在access_ok、copy_from_user、copy_to_user 等幾個函數使用中出現漏洞。

 著名exploit網站Exploit Database對于CVE-2017-5123的介紹

鏈接地址:https://www.exploit-db.com/exploits/43029/

   漏洞針對的Linux內核版本:

 Linux version 4.14.0-rc4+ ([email protected]) (gcc version 7.1.1 20170621 (GCC)) #1 SMP Mon Oct 16 21:54:35 CEST 2017

Android系統不受此漏洞影響。

 

0x1 測試環境

virtualbox虛擬機ubuntu 14.04上測試。測試流程和視頻中完全一樣。

https://asciinema.org/a/BeRNWtrX27yF28CMeflqHQT0H

exploit代碼不是在Host系統中測試,通過qemu掛載有漏洞的kernelfilesystem 鏡像測試exploit

 

0x2 漏洞原理

漏洞出現在waitid系統調用中,因為沒有檢查用戶態傳入的指針的有效性導致用戶態可以任意內核地址寫漏洞。

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

patch是調用access_ok檢查infop參數的有效性。

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=96ca579a1ecc943b75beba58bebb0356f6cc4b51

 

patch中添加了檢查參數infop用戶態指針是否可以寫入的檢測。如果infop指向無效地址,或者內核地址空間都是非法的。

 

0x3 Exploit 分析

github上有人提供了一份利用內核任意地址寫漏洞本地提權的exploit,要執行此 exploit 必須關閉mmap_min_addr  SMEP 防護。

這份exploit 比較簡單,學習的重點放在如何修改的內核內存達到劫持控制流。

 

首先exploit從內核符號表獲取了commit_creds,prepare_kernel_cred函數的地址。 commit_creds(cred *)函數可以更新當前進程的cred憑據。prepare_kernel_cred()函數可以創建一個憑據。

接下來申請一片內存用來存儲shellcode。這里從0地址開始映射了4096 byte內存。

 

這里先是向0xffffffff81f3f45a 地址寫入0, 然后跳轉到get_root 函數處去刷新當前進程的 憑據, 刷新憑據的代碼使用通用的提權代碼,如下:

上述權限提升有效載荷會分配一個新的憑證結構(uid=0, gid=0等)并將它應用到調用進程中當前這個exploit就是使用的這個payload達到提權的目的。因為關閉SMEP所以免去了用rop翻轉smep繞過SMEP的限制。

最后該觸發漏洞漏洞了,這里先調用waitid(1, pid,0xffffffff81f3f45a,…)修改內核地址0xffffffff81f3f45a的內容,然后調用fork函數。一般的套路是修改內核data段內一個全局結構體中的函數指針地址,然后在調用此函數指針跳轉到我們的目標地址。

內核中有很多這樣的結構,比如avc_callbacks、cgroup_subsys、have_fork_callback 等等。這里作者只給了一個地址沒有說明是那個函數,需要動態調試內核到這個地址查看內容才能知道使用的是哪個函數指針。

目前受到網絡影響沒辦法調試漏洞,暫且分析作者的調試日志,可以發現漏洞觸發過程的調用棧。

Trace:

[    6.371828]  ? cgroup_can_fork+0x63/0xb0

[    6.372082]  copy_process.part.55+0x115f/0x19e0

[    6.372328]  _do_fork+0xbd/0x370

[    6.372454]  SyS_clone+0x14/0x20

[    6.372560]  do_syscall_64+0x4e/0x100

[    6.372669]  entry_SYSCALL64_slow_pat

根據調用棧我們就知道是修改了fork函數實現中的某個函數指針,下面繼續分析源代碼。

 

(linux/kernel/cgroup/cgroup.c)

cgroup_subsys結構體數組是一個全局變量伴隨內核啟動初始化完畢,這里調用cgroup_subsys結構體中的can_fork函數指針,所以可以猜測 0xffffffff81f3f45a地址就在 cgroup_subsys對象附近。

 

再來看下waitid是如何寫入00xffffffff81f3f45a地址。

waitid中多處調用unsafe_put_user()infop指針(0xffffffff81f3f45a)寫入數據。

exploit中調用完waitid緊接著調用了fork函數觸發了can_fork函數跳轉到0地址執行shellcode。

漏洞分析和exploit的原理分析完畢,我在本地做了測試非常穩定的exploit,感興趣可以看看文章開頭的提權視頻。

 

0x4 exploit 代碼說明

exploit 執行

exploit代碼執行順序:

1、run_kernel.shqemu中啟動vul linux(開啟靶?。?,從qemu 啟動日志和腳本可以看到系統防護的狀態(NX開啟了,kaslr關閉了)

2、setup_exploit.sh1執行完以后,當前的終端會進入vul linux系統,此時是root 用戶。此腳本會關閉mmap_min_addr限制允許exploit mmap 0地址,并輸出”./exploit 0xffffffff81f3f45a”。這里要啟動一個普通用戶,準備提升權限。

3、./exploit 0xffffffff81f3f45a2中輸出了這條命令,exploit是二進制程序沒有源代碼,可以逆向或者自己分析漏洞寫exp。此exp已經具有任意內核地址寫的能力。

編譯kernel & filesystem方法

kernelfilesystem的編譯方法在 kernel_compilation_cheatsheet.md文件中。

安裝軟件

 

 

0x5 測試截圖:

 

exploit 代碼:

https://github.com/nongiach/CVE/tree/master/CVE-2017-5123

 

關于SURFSRC

任子行網絡安全攻防實驗室(SURFSRC)成立于2017年,以網絡安全攻防技術為核心,專注于網絡安全技術研究及安全攻防體系搭建。

實驗室重點關注APT攻擊與防御技術、惡意代碼對抗、基于主機與網絡的取證技術、網絡惡意流量檢測、二進制漏洞攻防、非接觸式移動端漏洞與攻擊(包括AndroidiOS平臺上的Wi-Fi、藍牙等)以及Web安全研究等前沿網絡安全技術、網絡攻防滲透、惡意攻擊溯源等網絡信息安全攻防技術研究與應用,洞察網絡安全前沿威脅,提升企業運維安全效率,為企業網絡信息安全護航。