在Linux下用gdb檢測內核rootkit

2020-12-01 IT168

    文涉及的技術原理都不是新的,對研究人員沒什麼特別大的價值,不過對工程人員應急相應來說不失為一種新的方法。

理解攻擊向量

內核rookit通常以系統調用為攻擊目標,主要出於兩個原因:

a.在內核態劫持系統調用能以較小的代價控制整個系統,不必修太多東西;

b.應用層大多數函數是一個或多個系統調用不同形式的封裝,更改系統調用意味著其上層所有的函數都會被欺騙;

在kernel-2.4.27中大約有230多個系統調用,而kernel-2.6.9中大約有290多個系統調用,系統調用的個數取決於內核版本。完整的系統調用列表可以在 /usr/include/asm/unistd.h頭文件中獲得。

另外需要注意的是入侵者並不更改所有的系統調用,而只是替換其中一些比較有用的。這些系統調用如表一所示,他們可以被系統管理員及入侵檢測系統(OS kernel級IDS)監視,可以用man命令得到每個系統調用的完整描述。

System call name Short description ID --------------------------------------------------------------------------------------- sys_read used for reading from files 3 sys_write used for writing to files 4 sys_open used to create or open files 5 sys_getdents/sys_getdents64 used to list a content of directories(also /proc) 141/220 sys_socketcall used for managing sockets 102 sys_query_module used for querying loaded modules 167 sys_setuid/sys_getuid used for managing UIDs 23/24 sys_execve used for executing binary files 11 sys_chdir used to change the directory 12 sys_fork/sys_clone used to create a child process 2/120 sys_ioctl used to control devices 54 sys_kill used to send signal to processes 37

我們注意上表的系統調用號,這些ID都是針對kernel-2.4.18-3的。

本文所有的例子都在Redhat7.3 kernel-2.4.18-3上通過測試,我們也可以在其他版本包括最新的2.6.x上用相似的步驟研究,不同之處可能在於2.6的一些內部結構,比如系統調用表的地址原來內含在系統調用處理例程system_call中,現在改成在syscall_call函數中。

更改系統調用表

當前的系統調用地址保存在系統調用表中,位於作業系統為內核保留的內存空間(虛擬地址最高1GB),系統調用入口地址的存放順序同/usr/include/asm/unistd.h中的排列順序,按系統調用號遞增。

在0x80軟中斷發生之前,對應的系統調用號被壓入eax寄存器,例如sys_write被調用時,其對應的系統調用ID:4會被壓入eax。

入侵者使用的第一種方法是:更改系統調用表中的系統調用地址,這樣系統調用發生時會跳轉到攻擊者自己編寫的函數去執行。通過觀察系統調用表中的系統調用入口地址,使用gdb我們可以比較容易檢測到這種攻擊行為。

原始的系統調用地址在內核編譯階段被指定,不會更改,通過比較原始的系統調用地址和當前內核態中的系統調用地址我們就可以發現系統調用有沒有被更改。原始的系統調用地址在編譯階段被寫入兩個文件:

a.System.map該文件包含所有的符號地址,系統調用也包含在內;

b.系統初始化時首先被讀入內存的內核映像文件vmlinux-2.4.x;

vmlinux-2.4.x文件通常以壓縮的格式存放在/boot目錄下,所以在比較之前必須解壓這個文件,另一個問題是:我們的比較的前提是假設system.map及vmlinuz image都沒有被入侵者更改,所以更安全的做法是在系統乾淨時已經創建這兩個文件的可信任的拷貝,並創建文件的md5 hash。

原文中也列舉了一個內核模塊[gcc -c scprint.c -I/usr/src/`uname -r`/include/ ]使用該模塊列印系統調用地址,並自動寫入syslog,這樣可以進行實時的比較。

在大多數被裝載內核後門情況中,內核在系統初始化之後才被更改,更改發生在加載了rootkit的module或者被植入直接讀寫/dev/kmem的on-the-fly kernel patch之後。而通常情況下rootkit並不更改vmlinuz和system.map 這兩個文件,所以列印這兩個文件中的符號地址就可以知道系統原始的系統調用地址,系統當前運行中的系統調用地址(可能被更改)可以同過/proc下的kcore文件得到,比較兩者就知道結果。

1.首先找出系統調用表地址:

[root@rh8 boot]# cat System.map-2.4.18-13 | grep sys_call_table c0302c30 D sys_call_table

2.使用nm命令可以列印出未被strip過的image文件中所有的符號地址:

[root@rh8 boot]# nm vmlinux-2.4.18-13 | grep sys_call_table c0302c30 D sys_call_table

使用gdb可以列印出所有的系統調用入口地址,這些對應的地址在內核原始碼的entry.S文件中定義,例如:

entry 0 (0xc01261a0)是sys_ni_syscall系統調用 entry 1 (0xc011e1d0)是sys_exit系統調用 entry 2 (0xc01078a0)是sys_fork系統調用 #gdb /boot/vmlinux-2.4.* (gdb) x/255 0xc0302c30 0xc0302c30 <sys_call_table>: 0xc01261a0 0xc011e1d0 0xc01078a0 0xc013fb70 0xc0302c40 <sys_call_table+16>: 0xc013fcb0 0xc013f0e0 0xc013f230 0xc011e5b0 0xc0302c50 <sys_call_table+32>: 0xc013f180 0xc014cb10 0xc014c670 0xc0107940 0xc0302c60 <sys_call_table+48>: 0xc013e620 0xc011f020 0xc014bcd0 0xc013e9a0 ...

我們也可以通過系統調用名列印出系統調用的地址:

(gdb) x/x sys_ni_syscall 0xc01261a0 <sys_ni_syscall>: 0xffffdab8 ((gdb) x/x sys_fork 0xc01078a0 <sys_fork>: 0x8b10ec83

要列印出當前運行系統中的系統調用地址我們必須給gdb加兩個參數:

a.第一個參數是內核映像文件vmliux-2.4.x

b.第二個參數是/proc/kcore二進位文件

#gdb /boot/vmlinux-2.4.* /proc/kcore (gdb) x/255x 0xc0302c30 0xc0302c30 <sys_call_table>: 0xc01261a0 0xc011e1d0 0xc01078a0 0xc88ab11a <<-- 0xc0302c40 <sys_call_table+16>: 0xc013fcb0 0xc013f0e0 0xc013f230 0xc011e5b0 0xc0302c50 <sys_call_table+32>: 0xc013f180 0xc014cb10 0xc014c670 0xc0107940 0xc0302c60 <sys_call_table+48>: 0xc013e620 0xc011f020 0xc014bcd0 0xc013e9a0

相關焦點

  • 嵌入式Linux的GDB調試環境建立
    假定在debug下編譯gdb套件,你前面已經設定了TARGET,PREFIX參數。其中TARGET是你的目標板,我的是arm-linux,PREFIX是你要安裝的目標文件夾。$tar xvzf gdb-5.2.1.tar.gz $mkdir debug/build-gdb $cd build-gdb $..
  • Linux下C編程基礎之:本章小結與思考與練習
    再接下來,本章介紹了gcc編譯器的使用、函數庫的創建與使用以及gdb調試器的使用,並結合具體的實例進行講解。雖然它們的選項比較多,但是常用的並不多,讀者著重掌握筆者例子中使用的一些選項即可。之後,本章又介紹了make工程管理器的使用,這裡包括makefile的基本結構、makefile的變量定義及其規則和make的使用。
  • Linux2.6內核驅動移植參考
    作者:晏渭川 隨著Linux2.6的發布,由於2.6內核做了教的改動,各個設備的驅動程序在不同程度上要 進行改寫。為了方便各位Linux愛好者我把自己整理的這分文檔share出來。該文當列舉 了2.6內核同以前版本的絕大多數變化,可惜的是由於時間和精力有限沒有詳細列出各個 函數的用法。
  • 升級Ubuntu Linux 內核的幾種不同方法
    方法 1 - 使用 dpkg 升級 Linux 內核(手動方式)這個方法可以幫助你從kernel.ubuntu.com網站手動下載可用的最新 Linux 內核。如果你打算安裝最新版(而不是穩定版或者正式發布版),那這種方法對你會很有用。從以上連結下載 Linux 內核版本。編寫這個指南的時候,最新的可用版本是 5.0-rc1,最新的穩定版是 v4.20。
  • 從RTOS到Linux的應用移植
    在具體的應用移植過程中,還應考慮在Linux系統下解決上層應用實時響應底層硬體中斷,應用層與內核層的異步通信、數據交換,以及多進程、多線程的設計等問題。多任務在內核的管理、調度下並行執行,而且任務都是無限循環的,持續實現其功能。多任務實時作業系統示意圖如圖2所示。
  • Linux如何安裝軟體
    安裝gdb為例確定依賴關係gcc -> g++ -> gdb,gdb依賴g++,g++依賴gccgccrpm -ivh cpp-4.1.2-42.el5.i386.rpmrpm -ivh kernel-headers-2.6.18-92.el5.i386.rpmrpm -ivh glibc-headers
  • linux下安裝虛擬機,完美在linux系統下運行通達信軟體
    現在越來越多的人使用linux系統,現在很多的國產作業系統都是基於linux內核上的。雖說不少的軟體都可以運行在linux的系統上。但是對於股票軟體來說在linux上的使用是一個硬傷。能夠運行在linux下的國內股票軟體少之又少。
  • 一張圖看懂Linux內核中Percpu變量的實現
    但你知道嗎,不僅是在程式語言中,在linux內核中,也有一個類似的機制,用來實現類似的目的,它叫做percpu變量。percpu變量,顧名思義,就是對於同一個變量,每個cpu都有自己的一份,它可以被用來存放一些cpu獨有的數據,比如cpu的id,cpu上正在運行的線程等等,因該機制可以非常方便的解決一些特定問題,所以在內核編程中被廣泛使用。
  • ARM64 Linux 內核頁表的塊映射
    我們看看這種情況下的頁表,我們既可以用最終的【20:12】對應的 PTE 映射項,以 4K 為單位,進行虛擬地址到物理地址的映射;又可以以【29:21】對應的 PMD 映射項,以 2M 為單位,進行虛擬地址到物理地址的映射。
  • Linux系統的Linux應該怎麼讀?正確讀法在這裡,很多人都讀錯了!
    1、linux發音五花八門版本頗多,見到和聽到的不下10種。根據linux的創始人Linus Torvalds的說法,Linux的發音和「Minix」是押韻的。大致和「利訥克斯」的音類似(注意不是利牛克斯、利努克斯或者利尼克斯但是瑞典語,英式英語,美國東西海岸讀法都不同,無所謂的,看視頻,那些linux大師都亂讀的 linux是linus製作的,本不叫linux,因為和unix兼容,所以一開始同學把它的代碼放在ftp上一個取名為「linux」的文件夾內,慢慢的人們叫它linux了答:沒中文名,只有中文版本比較流行的RED HAT
  • 從串口驅動到Linux驅動模型,想轉Linux的必會!
    並不是linux下的串口驅動。引入此圖旨在讓讀者感性的認識到串口控制臺的功能是什麼。下面正式開始對串口打開。發送。接收函數的分析。這裡向前引用一個函數。就是linux內核中幾種2440晶片通用的串口發送函數s3c24xx_serial_start_tx。
  • 數字溫度傳感器DS1621在Linux下的IIC接口驅動設計
    DS1621可作為恆溫控制器單獨使用,也可通過2線接口在ARM的控制下完成溫度的測量及計算。可以通過寄存器設置調整。DS1621無需外圍元件即可測量溫度,結果以9位數字量(兩字節)給出,測量範圍為-55~+155℃,精度為0.5℃:典型轉換時間為1 s。
  • Linux應急響應手冊
    本文從實戰出發,歸納總結在Linux環境下,當伺服器遭受入侵時的常用的應急響應流程和方法。      業界有個應急響應參考模型,叫做PDCERF方法,它把應急響應體系分為六個階段來處理,這六個階段分別是準備(Perparation)、檢測(Detection)、遏制(Containment)、根除(Eradication)、恢復(Recovery)、跟蹤(Follow-up)。
  • 【連載】嵌入式Linux開發教程:Linux內核
    但當時的管理員並不喜歡「Freax」這個名稱,並以「Linus’s Minix」之意,將Freax放到了一個名為「Linux」的目錄下,之後便一直用Linux這個名稱。 Linux誕生、發展和壯大於網絡,目前依然掌控於Linux社區,遍布全球數以萬計的黑客和志願者參與Linux開發,也有商業公司為Linux貢獻代碼。
  • 嵌入式Linux開發環境的搭建之:嵌入式開發環境的搭建
    搭建交叉編譯環境的方法很多,不同的體系結構、不同的操作內容甚至是不同版本的內核,都會用到不同的交叉編譯器,而且,有些交叉編譯器經常會有部分的bug,這都會導致最後的代碼無法正常地運行。因此,選擇合適的交叉編譯器對於嵌入式開發是非常重要的。
  • ARM Linux根文件系統Root Filesystem的製作
    在使用devfs的內核裡如果沒有/dev,根本見不到Shell啟動的信息,因為內核找不到/dev/console;在使用udev的系統裡,也事先需要在/dev下建立console和null這兩個節點。關於devfs和udev的區別,網上很多文章說。當然如果你的內核已經不支持devfs了(2.6.12以後),可以使用純純的靜態節點。也就是用mknod人工生成。