某Linux服務器發現異常現象如下圖,確定被植入Rootkit,但運維人員使用常規Rootkit檢測方法無效,對此情況我們還可以做什么?
圖1 被植入Rootkit的Linux服務器
所有暗鏈的html文件ls均看不到。
使用ls -al 絕對路徑,能看到,但無法刪除。
這些暗鏈的uid和gid都很奇特 分別為 2511744398:4043361279 。
對任意文件執行chown 2511744398:4043361279 其表現會和暗鏈文件相同。
將硬盤nfs掛載到正常系統上,現象無任何變化。
一般來說,Rootkit檢測方式有以下幾種:
1. 可信任Shell——使用靜態編譯的二進制文件:lsof、stat、strace、last、……
2. 檢測工具和腳本:rkhunter, chkrootkit, OSSEC
3. LiveCD——DEFT、Second Look、 Helix
4. 動態分析和調試:使用gdb根據System.map和vmlinuz image分析/proc/kcore
5. 直接調試裸設備:debugFS
在分析這幾種檢測方法的優劣之前,我們先通過圖2了解一下Linux Rootkit的一般實現原理
圖2 Linux中系統命令執行的一般流程
在Ring3層(用戶空間)工作的系統命令/應用程序實現某些基礎功能時會調用系統.so文件注1。而這些.so文件實現的基本功能,如文件讀寫則是通過讀取Ring0層(內核空間)的Syscall Table注2(系統調用表)中相應Syscall(系統調用)作用到硬件,最終完成文件讀寫的。
那么如果中了Rootkit,這個流程會發生什么變化呢?下面通過圖3來了解一下。
圖3 Rootkit的一般執行流程
Rootkit篡改了Syscall Table中Syscall的內存地址,導致程序讀取修改過的Syscall地址而執行了惡意的函數從而實現其特殊功能和目的。
上圖僅僅是列舉了一種典型的Rootkit工作流程,通過修改程序讀取Syscall的不同環節可以產生不同類型的Rootkit,我們簡單羅列一下。
Rootkit部分實現方式:
1. 攔截中斷-重定向sys_call_table,修改IDT
2. 劫持系統調用-修改sys_call_table
3. inline hook-修改sys_call,插入jmp指令
這部分不是本文的重點,不再贅述。了解了Rootkit實現原理,我們再回過來對比一下常規Rootkit檢測方式的優劣。
對于使用靜態編譯的二進制文件的檢測方式,如果Rootkit修改了Syscall,那么這種方法產生的輸出也是不可靠的,我們無法看到任何被Rootkit隱藏的東西。
那么如果使用Rootkit檢測工具呢,我們簡單分析一下rkhunter的檢測原理。
在rkhunter腳本文件中,scanrootkit函數部分代碼如下:
圖4 rkhunter中的scanrootkit函數
注:其安裝腳本中定義了以下兩個變量
#!bash
RKHTMPVAR="${RKHINST_SIG_DIR}"
RKHINST_SIG_DIR="${RKHINST_DB_DIR}/signatures"
圖5 Signatures目錄中的文件列表——Rootkit簽名列表
從上面這段代碼我們可以看出rkhunter掃描Rootkit調用了3個重要的變量:SCAN_FILES, SCAN_DIRS,SCAN_KSYMS,用于每種Rootkit的檢查。
下面的四幅圖分別是Adore和KBeast兩個Rootkit檢測的具體代碼。
圖6 rkhunter中經典Rootkit Adore的檢測流程
圖7 rkhunter中檢測Adore的文件和目錄的清單
圖8 rkhunter中Rootkit KBeast的檢測流程
圖9 rkhunter中檢測KBeast的文件和目錄的清單
根據以上分析,我們可以看出rkhunter僅僅是檢查已知Rootkit組件默認安裝路徑上是否存在相應文件,并比對文件簽名(signature)。這種檢測方式顯然過于粗糙,對修改過的/新的Rootkit基本無能為力。
而另一款流行的Rootkit檢測工具chkrootkit,其LKM Rootkit檢測模塊源文件為chkproc.c,最后更新日期為2006.1.11日。檢測原理與rkhunter大致相似,也主要基于簽名檢測并將ps命令的輸出同/proc目錄作比對。在它的FAQ中Q2的回答也印證了我們的結論。
圖10 chkrootkit的FAQ之Q2
分析了常見的Rootkit檢測工具的實現原理,我們再看一下使用LiveCD檢測這種方式有哪些局限性。
使用LiveCD意味著使用一純凈的光盤操作系統掛載原有存儲對可疑文件做靜態分析/逆向,以便了解Rootkit執行邏輯,依賴的so/ko文件有哪些,加載的配置文件是什么。那么,如果事先沒有找到一些Rootkit的相關文件,直接對整個文件系統做逐一排查,無疑是一個繁冗的過程。而且,這種方式的使用前提是應急響應人員必須能物理接觸服務器,這對托管在機房的環境很不方便。實際上,使用LiveCD在Rootkit清除或司法取證環節上更為常見,而不是其前置環節。
根據以上分析,我們簡單總結一下Rootkit檢測方式的效果,見下表.
Rootkit檢測方式對比
檢測方式 | 局限/缺陷 |
---|---|
使用靜態編譯的二進制文件 | 工作在用戶空間,對Ring0層的Rootkit無效。 |
工具rkhunter,chkrootkit | 掃描已知Rootkit特征,比對文件指紋,檢查/proc/modules,效果極為有限。 |
LiveCD:DEFT | Rootkit活動進程和網絡連接等無法看到,只能靜態分析。 |
GDB動態分析調試 | 調試分析/proc/kcore,門檻略高,較復雜。不適合應急響應。 |
DebugFS裸設備直接讀寫 | 不依賴內核模塊,繁瑣復雜,僅適合實驗室分析。 |
既然常規的Rootkit檢測方法有這樣那樣的缺陷,那有沒有更好的檢測方式呢?
下面我們詳細介紹一下基于內存分析Rootkit檢測方法。
Rootkit難以被檢測,主要是因為其高度的隱匿特性,一般表現在進程、端口、內核模塊和文件等方面的隱藏。但無論怎樣隱藏,內存中一定有這些方面的蛛絲馬跡,如果我們能正常dump物理內存,并通過debug symbols.和kernel`s data structure來解析內存文件,那么就可以對系統當時的活動狀態有一個真實的“描繪”,再將其和直接在系統執行命令輸出的“虛假”結果做對比,找出可疑的方面。下面簡述一下部分原理。
在Linux系統中查看進程一般執行的是ps –aux命令,其實質是通過讀取/proc/pid/來獲取進程信息的。而在內核的task_struct注3(進程結構體)中,也同樣包含進程pid、 創建時間、映像路徑等信息。也就是說每個進程的相關信息都可以通過其對應task_struct內存地址獲取。而且,每個task_struct通過next_task和prev_task串起成為一個雙向鏈表,可通過for_each_task宏來遍歷進程。基于這個原理我們可以先找到PID為0的init_task symobol(祖先進程)的內存地址,再進行遍歷就能模擬出ps的效果。部分細節可參考下圖。
圖11 內核中的task_struct
此外,Linux內核中有一個東西叫PID Hash Chain,如圖12所示,它是一個指針數組,每個元素指向一組pid的task_struct鏈表中的元素 ,能夠讓內核快速的根據pid找到對應的進程。所以分析pid_hash也能用來檢測隱藏進程和獲取相應進程信息,并且效率更高。
圖12 內核中的PID Hash Chain
在task_struct中,mm_struct注4描述了一個進程的整個虛擬地址空間,進程映射主要存儲在一個vm_area_struct的結構變量mm_rb注5和mmap 中,大致結構如下圖所示
圖13 mm_struct(內存描述符)的結構
每一個vm_area_struct節點詳細記錄了VMA(virtual memory area)的相關屬性,比如vm_start(起始地址)、vm_end(結束地址)、vm_flags(訪問權限)以及對應的vm_file(映射文件)。從內存中我們得到信息就相當于獲得了/proc/
Linux中的lsof(List Open Files)實質是讀取/proc/pid/文件夾中的信息。而這些信息通過task_struct也能獲取。
圖14 內核中的task_struct細節
task_struct的structure(數據結構)中files指向files_struct(文件結構體),用于表示當前進程打開的文件表。其structure中有一個fd_array(文件描述符數組),數組中的每個元素fd(File Descriptor文件描述符),都代表一個進程打開的文件。而每個File Descriptor的structure中又包含了目錄項dentry,文件操作f_ops等等。這些足以讓我們找到每個進程打開的文件。
另,當某個文件的f_op structure 成員是socket_file_ops 或者其dentry.d_op 為sockfs_dentry_operations時,則可以將其轉為為相應的inet_sock structure,最終得到相應的網絡信息。
后滲透測試階段,攻擊者常使用history –c命令來清空未保存進.bash_history文件的命令歷史。而在Rootkit中,通過配置HISTSIZE = 0 或將HISTFILE = /dev/null也是一種常見的隱藏命令歷史的方法。對于后者,由于bash進程的history也記錄在相應的MMAP中(其對應的宏定義為 HISTORY_USE_MMAP注6),通過history_list()函數相應的mmap數據也可以還原其歷史記錄。
圖15 bash 4.0源碼histfile.c文件中history_do_write函數功能圖示.
通過遍歷module list上所有的struct module來檢查Rootkit是一種代替lsmod命令的的方法。但是如果Rootkit把自己的LKM從module list摘除,但仍加載在內存中,這種方法就不起作用了。
圖16 內核中Kernel Module List
不過,Rootkit很難在/sys/module/目錄中隱藏,所以我們仍可通過遍歷Sysfs文件系統來檢查隱藏的內核模塊。
在2.6.29內核的以前版本,Rootkit可以將用戶態的進程通過設置其effective user ID和effective group ID為0(root)進行特權提升。而在后面的版本中,kernel引入了'cred' structure。為此,Rootkit與時俱進,通過設置同某個root權限進程一樣的'cred' structure 來應對這種改進。所以通過檢查所有進程的'cred' structure 能更好的發現活動的Rootkit。
限于篇幅,本文不再介紹更多的原理和細節,簡單總結一下這種方法的的大致流程。
1 制作目標Linux服務器的profile
2 Dump完整的物理內存
3 使用profile解析內存映像文件,輸出系統信息
圖17 基于內存分析檢測Rootkit原理示意圖
基于內存分析檢測Rootkit的方法比對常規的檢測方法有較大的優勢,但它不是萬能的,如果被Bootkit之類的高級Rootkit干擾,Dump的物理內存不正確或不完整,后面的步驟就是空中閣樓。另外也要確保制作Profile時需要的System.map沒有被篡改或者直接使用同一內核版本號的Linux發行版中的文件來替代。
通過內存分析檢測Rootkit的工具目前不是很多,各有優劣。司法取證領域的開源工具Volatility是這方面的佼佼者,推薦各位同仁使用并貢獻代碼。對內存檢測分析技術感興趣的同學,歡迎和我交流討論。EOF
注1:Linux中的so(shared object)文件近似于Windows下的dll(dynamic link library)文件,均用來提供函數和資源。
注2:Syscall Table一般可以通過查看/boot/System.map文件來獲取其內容
注3: Process Descriptor:To manage processes, the kernel must have a clear picture of what each process is doing. It must know, for instance, the process's priority, whether it is running on a CPU or blocked on an event, what address space has been assigned to it, which files it is allowed to address, and so on. This is the role of the process descriptor — a task_struct type structure whose fields contain all the information related to a single process.
注4:mm_struct概要了相應程序所使用的內存信息,比如所有段(segment)、各個主要段的始末位置、使用常駐內存的總大小等等,一般稱之為memory descriptor(內存描述符)
注5:mm_rb:Red black tree of mappings.
注6:HISTORY_USE_MMAP定義見bash-4.0-src/lib/readline/histfile.c 475行,具體可參見http://sourcecodebrowser.com/bash/4.0/histfile_8c_source.html.
http://www.rootkitanalytics.com/kernelland/linux-kernel-rootkit.php https://media.blackhat.com/bh-us-11/Case/BH_US_11_Case_Linux_Slides.pdf https://www.safaribooksonline.com/library/view/understanding-the-linux/0596005652/ch03s02.html http://www.wowotech.net/linux/19.html http://www.lenky.info/archives/2012/04/1424 http://code.google.com/p/volatility/