Linux下基於記憶體分析的Rootkit檢測方法

wyzsk發表於2020-08-19
作者: 路人甲 · 2015/01/23 9:52

0x00 引言


某Linux伺服器發現異常現象如下圖,確定被植入Rootkit,但運維人員使用常規Rootkit檢測方法無效,對此情況我們還可以做什麼?

enter image description here

圖1 被植入Rootkit的Linux伺服器

所有暗鏈的html檔案ls均看不到。

使用ls -al 絕對路徑,能看到,但無法刪除。

這些暗鏈的uid和gid都很奇特 分別為 2511744398:4043361279 。

對任意檔案執行chown 2511744398:4043361279 其表現會和暗鏈檔案相同。

將硬碟nfs掛載到正常系統上,現象無任何變化。

0x01 Rootkit實現方式和檢測方法


一般來說,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的一般實現原理

enter image description here

圖2 Linux中系統命令執行的一般流程

在Ring3層(使用者空間)工作的系統命令/應用程式實現某些基礎功能時會呼叫系統.so檔案注1。而這些.so檔案實現的基本功能,如檔案讀寫則是透過讀取Ring0層(核心空間)的Syscall Table注2(系統呼叫表)中相應Syscall(系統呼叫)作用到硬體,最終完成檔案讀寫的。

那麼如果中了Rootkit,這個流程會發生什麼變化呢?下面透過圖3來了解一下。

enter image description here

圖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函式部分程式碼如下:

enter image description here

圖4 rkhunter中的scanrootkit函式

注:其安裝指令碼中定義了以下兩個變數

#!bash
RKHTMPVAR="${RKHINST_SIG_DIR}"
RKHINST_SIG_DIR="${RKHINST_DB_DIR}/signatures"

enter image description here

圖5 Signatures目錄中的檔案列表——Rootkit簽名列表

從上面這段程式碼我們可以看出rkhunter掃描Rootkit呼叫了3個重要的變數:SCAN_FILES, SCAN_DIRS,SCAN_KSYMS,用於每種Rootkit的檢查。

下面的四幅圖分別是Adore和KBeast兩個Rootkit檢測的具體程式碼。

enter image description here

圖6 rkhunter中經典Rootkit Adore的檢測流程

enter image description here

圖7 rkhunter中檢測Adore的檔案和目錄的清單

enter image description here

圖8 rkhunter中Rootkit KBeast的檢測流程

enter image description here

圖9 rkhunter中檢測KBeast的檔案和目錄的清單

根據以上分析,我們可以看出rkhunter僅僅是檢查已知Rootkit元件預設安裝路徑上是否存在相應檔案,並比對檔案簽名(signature)。這種檢測方式顯然過於粗糙,對修改過的/新的Rootkit基本無能為力。

而另一款流行的Rootkit檢測工具chkrootkit,其LKM Rootkit檢測模組原始檔為chkproc.c,最後更新日期為2006.1.11日。檢測原理與rkhunter大致相似,也主要基於簽名檢測並將ps命令的輸出同/proc目錄作比對。在它的FAQ中Q2的回答也印證了我們的結論。

enter image description here

圖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檢測方法。

0x02 基於記憶體檢測和分析Rootkit


Rootkit難以被檢測,主要是因為其高度的隱匿特性,一般表現在程式、埠、核心模組和檔案等方面的隱藏。但無論怎樣隱藏,記憶體中一定有這些方面的蛛絲馬跡,如果我們能正常dump實體記憶體,並透過debug symbols.和kernel`s data structure來解析記憶體檔案,那麼就可以對系統當時的活動狀態有一個真實的“描繪”,再將其和直接在系統執行命令輸出的“虛假”結果做對比,找出可疑的方面。下面簡述一下部分原理。

1. 基於記憶體分析檢測程式


在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的效果。部分細節可參考下圖。

enter image description here

圖11 核心中的task_struct

此外,Linux核心中有一個東西叫PID Hash Chain,如圖12所示,它是一個指標陣列,每個元素指向一組pid的task_struct連結串列中的元素 ,能夠讓核心快速的根據pid找到對應的程式。所以分析pid_hash也能用來檢測隱藏程式和獲取相應程式資訊,並且效率更高。

enter image description here

圖12 核心中的PID Hash Chain

2. 基於記憶體分析Process Memory Maps(程式對映)


在task_struct中,mm_struct注4描述了一個程式的整個虛擬地址空間,程式對映主要儲存在一個vm_area_struct的結構變數mm_rb注5和mmap 中,大致結構如下圖所示

enter image description here

圖13 mm_struct(記憶體描述符)的結構

每一個vm_area_struct節點詳細記錄了VMA(virtual memory area)的相關屬性,比如vm_start(起始地址)、vm_end(結束地址)、vm_flags(訪問許可權)以及對應的vm_file(對映檔案)。從記憶體中我們得到資訊就相當於獲得了/proc/

相關文章