摘要:審計系統作為安全操作系統的重要組成部分,在系統監測中起著重要作用,它確保安全策略的正確實現和入侵檢測系統的建立。原始的基于應用的Linux審計體系存在固有的缺點,應該對此進行改善。該篇介紹了在Linux內核中安全審計系統的設計與實現。在Linux內核中實現了基于可加載內核模塊的安全審計模型并運用了一種新的基于復制中斷描述表的系統調用攔截的方法。此外,該系統能在內核中全面采集信息,并且采取了有效的方法保護審計系統自身的安全。
關鍵詞:安全審計;可加載內核模塊;中斷描述表
中圖分類號:TP311文獻標識碼:A文章編號:1009-3044(2008)14-20835-02
1 引言
通過對現實社會管理方式的模仿,審計被引入到計算機系統中并主要應用于監視系統行為。審計系統作為安全操作系統的重要組成,將用于監視,記錄和控制計算機系統的安全行為。它的主要功能是檢測和阻止非法用戶的系統入侵和提示合法用戶的錯誤操作。在公用的Linux操作系統中,日志機制實現了相似的功能。但是日志機制在審計粒度,審計安全和審計靈活性方面存在著明顯的缺陷。
現有的Linux的審計機制是基于應用層面的。典型的審計系統如“syslogd”(一種用于郵件收發的后臺程序)。它主要應用于從各種受限制的服務(klogd,httpd,inetd,etc)中獲取重要的信息,并且根據配置文件實現通訊處理。不同的類型有明顯不同的輸出模式并且這些輸出將被保存到不同的日志文件中。原始的Linux審計系統中有以下安全問題:首先,一旦某用于收集審計數據的外部服務程序被惡意用戶破壞,這些審計數據將不會被記錄下來,因為服務程序運行于用戶狀態。其次,即使審計信息在用戶狀態被收集,這些信息也是不充分,不詳細的。例如,只有系統調用名被記錄,而不會提供與其相關的其他信息。在者,這里沒有足夠的方法來保護已存在的日志文件。換句話說,這些日志文件能夠被其他用戶訪問,篡改和刪除。而且,沒有有效的方法去檢查,分析這些審計信息。因此,我們應該改善原始的Linux審計機制,加強審計日志安全性的管理。
在這篇文章中,提供了詳細的安全審計系統在Linux內核中的設計和實現。該系統實現了一種新的基于中斷描述表的系統攔截方法的調用。
2 安全審計系統的設計
內核作為操作系統中重要的組成部分,主要用于進程控制,內存尋址和管理,系統調用等方面。一個運行的Linux操作系統分為用戶狀態和內核狀態。就用戶程序而言,它們可以利用各種系統資源,如:文件,目錄,外設等,只有當系統調用時進入內核狀態,處理完成后,用戶程序又返回到用戶狀態。因此我們可以基于這種機制在內核中設置審計指針記錄關于系統運行狀態的詳細信息。這種審計機制的優越性在于:首先,所有的審計信息產生于內核。任何系統當前狀態的行為都能夠被真實的記錄下來,因此審計信息可以避免被惡意用戶在應用層破壞;其次,審計信息在內核中得到保存和處理,這種方式可以避免信息在黑客入侵后被刪除或破壞。
2.1 可加載內核模塊(LKM)
可加載內核模塊是一種擴充操作系統功能的機制。新的內核代碼可以在不重新編譯內核的狀況下通過動態加載直接執行。因此,可加載內核模塊被用于特定設備的驅動程序。所有的可加載內核模塊都包含兩種基本函數:“int init_module(void)”和“void cleanup_module(void)”,這用于模塊的初始化和模塊的卸載。被加載的模塊只是內核中運行的一段代碼,它可以訪問內核中許多機密部分。黑客可以利用KLM成功入侵內核,同樣,我們也可以利用這種技術保護內核。
2.2 系統調用攔截
系統調用作為應用程序與操作系統內核的接口,它返回調用操作系統特定功能的用戶程序的執行結果。當用戶程序執行相應的系統調用,將傳送給系統調用函數所需的所有信息。因此,我們可以在內核攔截這些系統調用,從這些特定的系統調用中獲取審計信息并通過設備文件將信息保存到用戶區域。在Linux中,指令“int ox80”被用于執行系統調用。做為用戶和內核的接口,外殼用于解釋和執行用戶命令和程序。分析用戶命令是外殼的基本操作。然后相關的子進程通過”execve()”函數得到執行。如果關于“execve()”的系統調用可以被攔截,我們就可以得到用戶所要執行的相關命令的審計信息。
主要的系統攔截過程如下:找到系統調用的入口(“sys_call_table[]”)在sys_call_table[]”中保存函數的原始入口指針;把用戶函數指針放入“sys_call_table[]”。在用戶程序中首先保存相關的系統調用審計信息,然后執行“execve()”。
為了避免系統調用被惡意的修改和取代,系統調用不能直接從“sys_call_table[]”輸出(內核版本2.4.18)。研究發現Linux內核對特定部分產生中斷,我們就可以通過復制中斷描述表(IDT)實現新的系統調用的攔截。
IDT是一個關于系統中斷或異常向量的表。每個向量有相應的中斷入口或異常處理程序。在Linux中有256個中斷向量;“ox80”是用來執行系統調用的。IDT由任務門,中斷門,陷阱門組成。系統調用利用中斷門。每個IDT的入口由8字節的描述符表示。中斷門由64位的描述符來表示。中斷程序的入口地址由“handler offset low”和“handler offset high”兩部分組成。當中斷發生,中斷程序就被調用,執行。IDT寄存器可以使IDT位于內存的任意空間,并且指定物理的入口地址和IDT的最大長度。指令“sidt“可以查找IDT在內存中的入口地址并且系統調用的入口地址可以在IDT中找到。當檢測到“system_call”的源碼(在“/arch/i386/kernet/entry.s”),我們可以發現申明“call SYMBOL_NAME(sys_call_table)(,%eax,4)”依照系統調用應用于轉變,同時“SYMBOL_NAME(sys_call_table)”的執行結果是“sys_call_table[]”的入口地址。因此,如果找到了申明“call something(,%eax,4)”,我們就可以找到“sys_call_table[]”的入口地址。這條申明的機器指令代碼是“oxff ox14 ox85”。
在找到“sys_call_table[]”的入口地址后,我們用新定制的函數“hacked_execve()”代替原有的函數“execve()”。新的函數主要用于從進程描述符中獲得審計信息,然后執行最初的外殼程序。進程描述符是“task_struct”結構體類型,由所有的進程信息組成。我們可以從“task_struct”結構體中獲得審計信息。由于進程描述符包含大量的信息,因此審計信息通常只包含“task_struct”結構體中的部分信息。
2.3 設備驅動程序
Linux內存被劃分為內核空間和用戶空間。一般用戶進程不能夠訪問內核空間,同樣內核空間也不能訪問用戶空間進程。這里有兩個方法用于建立可加載內核模塊程序(LKM)與用戶空間進程間的通訊:“proc”文件系統或設備文件。由于LKM與設備驅動程序的緊密聯系,所以利用設備驅動程序更為方便。
在“/dev”目錄下安裝一個虛擬的硬件設備(“hijacksyscalldev”)去傳遞內核空間與用戶空間的信息。當新的命令在內核中出現,相關的信息將通過設備驅動程序保存到虛擬硬件設備中。設備驅動實現打開,關閉和讀的功能。其間,用于掌管設備文件讀信息并保存到用戶空間的讀程序創建于用戶空間。這里有兩種類型的函數應用于內核空間與用戶空間信息交換:“copy_to_user()”,“copy_from_user()”和“put_user()”,“get_uset()”(在目錄“include/linux/sched.h”下可以找到這些函數的定義)。
3 安全審計系統的實現
在函數“int init_module(void)”中,設備已經注冊并且最初的“execve()”函數的指針也被保存。然后最初的“execve()”函數被新的特定函數“hacked_execve()”所取代。我們可以從用戶進程系統調用的特定信息中得到審計信息并用設備文件把這些信息保存到用戶空間。設備文件系統在Linux2.3.46版本中被引入,同時我們利用函數“devfs_register()”對設備進行注冊。
3.1 初始化
利用函數“int init_module(void)”, Int init_module(void){execve()=hacked_execve();hijacksyscalldev_handle=devfs_register(NULL,hijacksyscalldev,DEVFS_FL_DEFAULT,99,0,S_IFCHR,hijacksyscalldev_ops,NULL);}把安全審計系統加載到Linux操作系統內核中。
3.2 系統調用攔截
下面的部分介紹了結構體和函數在系統調用攔截中的應用的主要實現。定義一個“process_information”結構體。
Struct process_infortion{pid_t pid;//process ID
uid_t uid;gid_t gid;char comm[20]}
“process_infortion”結構體在這個例子中由四項組成,用于記錄進程的基本信息。更多的項可以依據審計的標準的不同進行添加。
函數“get_idt_addr”
_asm_volatite(\"sidt %o\": \"=m\" (idtr));//locate the entry address of IDT
Idt=”(unsigned long *)idtr[2];//locate the base address of IDT”
函數 \"get_sys_call_table_addr\"
struct _idt *pidt=((struct _idt*)idt_table)[128];
//locate the interrupt gate of system call
Return(void *)((pidt->offset_hige<<16)!pidt->offset_low);
//return the entry address of system call
函數\"get_call_addr\"
For(p=start;p //\"start\" is the entry address of \"system_call If(*(p+0)=='oxff' (p+1)=='ox14' (p+2)=='ox85') //search\" sys_call_table[] \"by char matching Return p+3;//return the address of \"sys_call_table[]\"}\" 3.3 設備驅動程序 設備驅動程序僅僅需要定義打開,關閉和讀的操作,讀操作是為了把數據從內核空間拷貝到用戶空間。 Ssize_t hijack_read(struct file *filp,char *buf,size_t buflen,loff_t *offset){ …… while(buflen *msg_ptr) {put_user(*(msg_ptr++),buf++);buflen--;bytes_read++;} return bytes_read; ……} 4 總結 審計是在計算機系統中用來監視、記錄和控制用戶活動的一種機制,它的主要目的是檢測和阻止非法用戶對計算機系統的入侵,并顯示合法用戶的誤操作。它是安全操作系統的重要組成部分。這篇文章介紹了安全審計系統在Linux內核中的設計和實現。該系統利用LKM在內核中實現了審計功能,并且運用了基于IDT的系統調用攔截函數。與原始的應用層審計機制相比,該系統擴展了審計范圍,實現了更廣泛的信息收集。同時該系統介紹了一種更靈活的審計信息構造函數,適應不同的審計標準。系統調用攔截函數對入侵者是隱藏的,它能夠更有效保護審計系統的安全。 參考文獻: [1] 建偉. 安全審計追蹤技術論述[J]. 信息安全與通訊保密,2001.7. [2] P.Chen, Y.H.Zhang, J.Y.Song, C. Zhao. \"Design and Implementation of Audit System in Linux Kernel (in Chinese), Journal of PLA University of Science and Technology, vol. 5,no.3,pp.13-16,2004. [3] H.Chen, W.C.Shi, H.L.Liang, Y.F.Sun. \"Design and Implementation of Kernel Level Secure Auditing Systems in Operating System (in Chinese),\" Computer Science,vol.31,no.8,pp.173-175,2004.