使用ICMP协议绕过防火墙拦截

    通常防火墙默认是允许用户使用Ping一个网络地址的,而我们知道Ping的过程其实是发送和接收ICMP报文的过程。我们看一下ICMP报文结构:

 

                  ICMP 8  |  代码 8  

                  校    验    和    16

                  标    识    符    16

                  序    列    码    16

当类型为8时是一个echo请求报文,当类型为0时是一个echo应答报文。Ping的时候发送的类型为8 接收的响应为0,所以防火墙对ICMP类型为0的报文是没有防的。这样我们就可以从这里着手做一些东西了。

 

先看代码,分为服务端和客户端。

 

  1. //ICMP Server.cpp
  2. #include <afxwin.h>
  3. #include <winsock2.h>
  4. #include <stdio.h>
  5. #include <urlmon.h> 
  6. #include <tlhelp32.h>
  7. #pragma comment(lib, "Urlmon.lib")
  8. #pragma comment(lib, "ws2_32.lib")
  9.                                                              
  10. #define STATUS_FAILED 0xFFFF
  11. #define MAX_PACKET 256
  12. #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
  13. #define SIO_RCVALL            _WSAIOW(IOC_VENDOR,1) 
  14. /* The IP header */
  15. typedef struct iphdr 
  16. {
  17.     unsigned char h_verlen;     //4位首部长度+IP版本号,4表示IPV4
  18.     unsigned char tos;              //8位服务类型TOS
  19.     unsigned short total_len;       //16位总长度(字节)
  20.     unsigned short ident;           //16位标识
  21.     unsigned short frag_and_flags;  //3位标志位
  22.     unsigned char ttl;              //8位生存时间 TTL
  23.     unsigned char proto;            //8位协议 (TCP, UDP 或其他)
  24.     unsigned short checksum;        //16位IP首部校验和
  25.     unsigned int sourceIP;          //32位源IP地址
  26.     unsigned int destIP;            //32位目的IP地址
  27. }IpHeader;
  28. //定义ICMP首部
  29. typedef struct _ihdr 
  30. {
  31.     BYTE i_type;        //8位类型
  32.     BYTE i_code;        //8位代码
  33.     USHORT i_cksum;     //16位校验和 
  34.     USHORT i_id;        //识别号(一般用进程号作为识别号)
  35.     USHORT i_seq;       //报文序列号 
  36.     ULONG timestamp;    //时间戳
  37. }IcmpHeader;
  38. char buffer[2048] = {0};//回传数据缓冲
  39. void decode_resp(char *,int ,struct sockaddr_in *);//ICMP解包函数
  40. void fill_icmp_data(char * icmp_data);  //icmp报文填充
  41. void sendICMP(void);        //发送
  42. char *ICMP_DEST_IP;
  43. USHORT checksum(USHORT *buffer, int size);  //校验位计算
  44. int main(int argc,char *argv[])
  45. {
  46.     char *icmp_data;
  47.     int bread,datasize,retval;
  48.     SOCKET sockRaw = (SOCKET)NULL;
  49.     WSADATA wsaData;
  50.     int timeout = 2000;
  51.     char *recvbuf;
  52.     DWORD dwBufferLen[10] ;
  53.     DWORD dwBufferInLen = 1 ;
  54.     DWORD dwBytesReturned = 0 ;
  55.     
  56.     struct sockaddr_in from, local;
  57.     int fromlen = sizeof(struct sockaddr_in);
  58.     if ((retval = WSAStartup(MAKEWORD(2,1),&wsaData)) != 0)
  59.     {
  60.         printf("WSAStartup failed: %s/n",retval);
  61.         ExitProcess(STATUS_FAILED);
  62.     }
  63.     //获取本机IP地址
  64.     char FAR name[MAX_PATH];
  65.     gethostname(name, MAX_PATH);
  66.     struct hostent FAR * pHostent;
  67.     pHostent = (struct hostent * )malloc(sizeof(struct hostent));
  68.     pHostent = gethostbyname(name);
  69.     sockRaw = WSASocket (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
  70.     if (sockRaw == INVALID_SOCKET)
  71.     {
  72.         printf("WSASocket() failed: %s/n",WSAGetLastError());
  73.         ExitProcess(STATUS_FAILED);
  74.     }
  75.     bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
  76.     if(bread == SOCKET_ERROR)
  77.         goto EXIT_SEGMENT;
  78.     datasize=0;
  79.     datasize += sizeof(IcmpHeader); 
  80.     icmp_data =(char*)xmalloc(MAX_PACKET);
  81.     recvbuf = (char*)xmalloc(MAX_PACKET);
  82.     if (!icmp_data) 
  83.     {
  84.         goto EXIT_SEGMENT;;
  85.     }
  86.     memset(icmp_data,0,MAX_PACKET);
  87.     local.sin_family=AF_INET;
  88.     local.sin_port= 0; 
  89.     local.sin_addr.S_un.S_addr = *(ULONG*)pHostent->h_addr_list[0];
  90.     if(bind(sockRaw, (struct sockaddr*)&local,sizeof(struct sockaddr)) == SOCKET_ERROR)
  91.     {
  92.         printf("bind errcode = %d/n", WSAGetLastError());
  93.         goto EXIT_SEGMENT;
  94.     }
  95.     //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
  96.     if(WSAIoctl(sockRaw,SIO_RCVALL,&dwBufferInLen, /
  97.         sizeof(dwBufferInLen),&dwBufferLen, /
  98.         sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL ) == SOCKET_ERROR)
  99.     {
  100.         printf("WSAIoctl errcode = %d/n", WSAGetLastError());
  101.         goto EXIT_SEGMENT;
  102.     }
  103.     for(;;) 
  104.     {
  105.         bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);
  106.         if (bread == SOCKET_ERROR)
  107.         {
  108.             if (WSAGetLastError() == WSAETIMEDOUT)
  109.                 continue;
  110.             printf("recv failed, errcode = %d/n", WSAGetLastError());
  111.             break;
  112.         }
  113.         decode_resp(recvbuf,bread,&from);
  114.         Sleep(200);
  115.         memset(recvbuf,0,sizeof(recvbuf));
  116.     }
  117. EXIT_SEGMENT:
  118.     if (sockRaw != INVALID_SOCKET) closesocket(sockRaw);
  119.     WSACleanup();
  120.     return 0;
  121. }
  122. //显示接收内容,并回传
  123. void decode_resp(char *buf, int nBytes,struct sockaddr_in *from) 
  124. {
  125.     IpHeader *iphdr;
  126.     IcmpHeader *icmphdr;
  127.     unsigned short iphdrlen;
  128.     iphdr = (IpHeader *)buf;
  129.     buf[nBytes] = 0;
  130.     
  131.     //屏蔽高四位version
  132.     iphdrlen = ((iphdr->h_verlen) & 0x0F)<<2 ; 
  133.     icmphdr = (IcmpHeader*)(buf + iphdrlen);
  134.     if(icmphdr->i_seq==1234)//密码正确则输出数据段
  135.     {
  136.         ICMP_DEST_IP=inet_ntoa(from->sin_addr);//取得ICMP包的源地址
  137.         printf("recv %d bytes from %s: %s/n", nBytes, ICMP_DEST_IP, buf + iphdrlen + 12);
  138.         
  139.         memset(buffer, 0x00, sizeof(buffer));
  140.         strcpy(buffer, "received ");
  141.         strcat(buffer, buf + iphdrlen + 12);
  142.         sendICMP();
  143.     }
  144. }
  145. //计算校验值
  146. USHORT checksum(USHORT *buffer, int size) 
  147. {
  148.     unsigned long cksum=0;
  149.     while(size >1) 
  150.     {
  151.         cksum+=*buffer++;
  152.         size -=sizeof(USHORT);
  153.     }
  154.     if(size ) 
  155.     {
  156.         cksum += *(UCHAR*)buffer;
  157.     }
  158.     cksum = (cksum >> 16) + (cksum & 0xffff);
  159.     cksum += (cksum >>16);
  160.     return (USHORT)(~cksum);
  161. }
  162. //填充ICMP报文
  163. void fill_icmp_data(char * icmp_data)
  164. {
  165.     IcmpHeader *icmp_hdr;
  166.     icmp_hdr = (IcmpHeader*)icmp_data;
  167.     icmp_hdr->i_type = 0;
  168.     icmp_hdr->i_code = 0;
  169.     icmp_hdr->i_id = (USHORT) GetCurrentProcessId();
  170.     icmp_hdr->i_cksum = 0;
  171.     icmp_hdr->i_seq =4321;
  172.     icmp_hdr->timestamp = GetTickCount(); //设置时间戳
  173.     memcpy(icmp_data + 12,buffer,strlen(buffer));
  174.     printf("echo back: %s/n", buffer);
  175. }
  176. //发送报文
  177. void sendICMP(void)
  178. {
  179.     SOCKET skt = (SOCKET)NULL;
  180.     struct sockaddr_in dest;
  181.     int bread,datasize,bwrote;
  182.     int timeout = 1000;
  183.     char *icmp_data;
  184.     if((skt=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED))
  185.     ==INVALID_SOCKET) ExitProcess(STATUS_FAILED);
  186.     if((bread=setsockopt(skt,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout)))==SOCKET_ERROR) 
  187.         goto EXIT_SEGMENT;
  188.     //设置发送超时
  189.     memset(&dest,0,sizeof(dest));
  190.     dest.sin_family = AF_INET;
  191.     dest.sin_addr.s_addr = inet_addr(ICMP_DEST_IP);
  192.     datasize=strlen(buffer);
  193.     datasize+=sizeof(IcmpHeader); 
  194.     icmp_data=(char*)xmalloc(MAX_PACKET);
  195.     if(!icmp_data)  goto EXIT_SEGMENT;
  196.     memset(icmp_data,0,MAX_PACKET);
  197.     //填充ICMP报文
  198.     fill_icmp_data(icmp_data); 
  199.     //计算校验和
  200.     ((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize); 
  201.     //发送报文
  202.     bwrote=sendto(skt,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest)); 
  203.     if (bwrote == SOCKET_ERROR)
  204.     {
  205.         if (WSAGetLastError() == WSAETIMEDOUT) printf("Timed out/n");
  206.         printf("sendto failed:%d",WSAGetLastError());
  207.         goto EXIT_SEGMENT;
  208.     }
  209.     printf("Send Packet to %s Success!/n", ICMP_DEST_IP);
  210. EXIT_SEGMENT:
  211.     if (skt != INVALID_SOCKET) closesocket(skt);
  212.     memset(buffer,0,sizeof(buffer));
  213.     Sleep(200);
  214. }

 

  1. #include <winsock2.h>
  2. #include <stdio.h>
  3. #include <stdlib.h> 
  4. #pragma comment(lib,"ws2_32.lib")
  5. char SendMsg[256];
  6. //IP报文头
  7. typedef struct iphdr 
  8. {
  9.     unsigned char h_verlen;     //4位首部长度+IP版本号,4表示IPV4
  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. }IpHeader;
  20. //ICMP报文头
  21. typedef struct _ihdr
  22. {
  23.     BYTE i_type;        //8位类型
  24.     BYTE i_code;        //8位代码
  25.     USHORT i_cksum;     //16位校验和
  26.     USHORT i_id;        //识别号(一般用进程号作为识别号)
  27.     USHORT i_seq;       //报文序列号
  28.     ULONG timestamp;    //时间截
  29. } IcmpHeader;
  30. #define STATUS_FAILED 0xFFFF 
  31. #define MAX_PACKET 256
  32. #define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s))
  33. void fill_icmp_data(char *, int);
  34. USHORT checksum(USHORT *, int);
  35. void decode_resp(char *,int ,struct sockaddr_in *);//ICMP解包函数
  36. void usage();
  37. int main(int argc, char *argv[])
  38. {
  39.     char *ICMP_DEST_IP; //目标主机的IP
  40.     char *recvbuf;
  41.     if(argc!=2)
  42.     {
  43.         usage();
  44.         return 0;
  45.     }
  46.     ICMP_DEST_IP=argv[1];//取得目标主机IP
  47.     WSADATA wsaData;
  48.     SOCKET sockRaw;
  49.     struct sockaddr_in dest,from;
  50.     int datasize;
  51.     int fromlen=sizeof(from);
  52.     char *icmp_data;
  53.     if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  54.     {
  55.         fprintf(stderr, "WSAStartup failed: %d/n", GetLastError());
  56.         ExitProcess(STATUS_FAILED);
  57.     }
  58.     sockRaw=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  59.     int timeout=1000;
  60.     setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
  61.     timeout=1000;
  62.     setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
  63.     memset(&dest,0,sizeof(dest));
  64.     dest.sin_addr.s_addr=inet_addr(ICMP_DEST_IP);
  65.     dest.sin_family=AF_INET;
  66.     usage();
  67.     for(;;)
  68.     {
  69.         memset(SendMsg, 0x00, sizeof(SendMsg));
  70.         fgets(SendMsg,1024,stdin);//取得命令行,保存在SendMsg数组中
  71.         if(!strcmp(SendMsg,"Q/n")||!strcmp(SendMsg,"q/n"))ExitProcess(0);
  72.         if(!strcmp(SendMsg,"/n"))continue;
  73.         SendMsg[strlen(SendMsg)-1] = 0;
  74.         datasize = strlen(SendMsg);
  75.         datasize +=sizeof(IcmpHeader);
  76.         printf("ICMP packet size is %d",datasize);
  77.         icmp_data= (char*)xmalloc(MAX_PACKET);
  78.         recvbuf= (char *)xmalloc(MAX_PACKET);
  79.         
  80.         memset(icmp_data,0, MAX_PACKET);
  81.         fill_icmp_data(icmp_data, datasize);
  82.         ((IcmpHeader *)icmp_data)->i_cksum=0;
  83.         ((IcmpHeader *)icmp_data)->i_cksum=checksum((USHORT *)icmp_data, datasize);
  84.         int bwrote=sendto(sockRaw, icmp_data, datasize, 0, (struct sockaddr *) &dest, sizeof(dest));
  85.         if (bwrote == SOCKET_ERROR)
  86.         {
  87.             if (WSAGetLastError() == WSAETIMEDOUT) printf("Timed out/n");
  88.             fprintf(stderr,"sendto failed: %d/n",WSAGetLastError());
  89.         }
  90.         if (bwrote<datasize ) //没有把所有的数据发送出去,也出错了。
  91.         {
  92.             if (sockRaw != INVALID_SOCKET) closesocket(sockRaw);
  93.             WSACleanup();
  94.             return 0;
  95.         }
  96.         printf("/nSend Packet to %s Success!/n",argv[1]);
  97.         memset(recvbuf,0,MAX_PACKET);
  98.         
  99.         int bread=recvfrom(sockRaw, recvbuf, MAX_PACKET, 0, (struct sockaddr *) &from, &fromlen);
  100.         if(bread == SOCKET_ERROR)
  101.         {
  102.             if(WSAGetLastError() == WSAETIMEDOUT)
  103.             {
  104.                 printf("timed out/n");
  105.                 continue;
  106.             }
  107.             break;
  108.         }
  109.         decode_resp(recvbuf, bread, &from);
  110.     }//end for
  111.     if (sockRaw != INVALID_SOCKET) closesocket(sockRaw);
  112.     WSACleanup();
  113.     return 0;
  114. }
  115. USHORT checksum(USHORT *buffer, int size)
  116. {
  117.     unsigned long cksum=0;
  118.     while(size > 1)
  119.     {
  120.         cksum+=*buffer++;
  121.         size-=sizeof(USHORT);
  122.     }
  123.     if(size)
  124.     {
  125.         cksum+=*(UCHAR *)buffer;
  126.     }
  127.     cksum=(cksum >> 16) + (cksum & 0xffff);
  128.     cksum+=(cksum >> 16);
  129.     return(USHORT) (~cksum);
  130. }
  131. void fill_icmp_data(char *icmp_data, int datasize)
  132. {
  133.     IcmpHeader *icmp_hdr;
  134.     char *datapart;
  135.     icmp_hdr= (IcmpHeader *)icmp_data;
  136.     icmp_hdr->i_type=0;
  137.     icmp_hdr->i_code=0;
  138.     icmp_hdr->i_id=(USHORT)GetCurrentProcessId();
  139.     icmp_hdr->timestamp =GetTickCount();
  140.     icmp_hdr->i_seq=1234;
  141.     datapart=icmp_data + sizeof(IcmpHeader);
  142.     memcpy(datapart,SendMsg,sizeof(SendMsg));
  143. void usage()
  144. {
  145.     printf("Usage: icmpclient RemoteIP/n");
  146.     printf("Ctrl+C or Q/q to Quite/n/n");
  147. }
  148. //显示回显内容
  149. void decode_resp(char *buf, int bytes,struct sockaddr_in *from) 
  150. {
  151.     IpHeader *iphdr;
  152.     IcmpHeader *icmphdr;
  153.     unsigned short iphdrlen;
  154.     
  155.     iphdr = (IpHeader *)buf;
  156.     //屏蔽高4位version
  157.     iphdrlen = ((iphdr->h_verlen) & 0x0F)<<2;
  158.     icmphdr = (IcmpHeader*)(buf + iphdrlen);
  159.     
  160.     if(icmphdr->i_seq == 4321)//密码正确则输出数据段
  161.     {
  162.         printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
  163.         printf(" IcmpType %d",icmphdr->i_type);
  164.         printf(" IcmpCode %d",icmphdr->i_code);
  165.         printf("/n");
  166.         printf("recv: %s/n",buf+iphdrlen+12);
  167.     }
  168. }

可以将Server端程序在另一电脑上运行,而Client端在本地运行,也可以在同一机器上运行。

运行完成后服务端等待数据到来,客户端通过输入可以向Server发送数据,服务端收到后解包进行回复,并回到等待接收数据状态,客户端接收服务端的响应,输出信息后继续等待用户输入。

 

这种方式的绕过其实是利用现有的“通行证”带一些自定义的东西,应该可以满足一些想法了呵呵...

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值