协议分析之TCP旁路阻断

阅读更多

一、阻断未建立起来的连接

      我们知道TCP的建立要经过3次握手,假设客户端C向服务器S请求连接

      1、C发送带有SEQ_C(随机)初始序列号的SYN报文给S

      2、S回复带有SEQ_S(随机)初始序列号和确认序列号ACK_S(必须是SEQ_C+1)的SYN报文给C

      3、C回复确认序列号ACK_C(取值为SEQ_S)给S

      整个过程如果正确的话,连接将会建立。

      通常需要进行阻断的情况是审计控制系统旁路监听内网。旁路监听的方式一般是将主交换机的数据镜像到控制系统,控制系统可以采用

libpcap捕获数据包。

     在这种情况下要阻断tcp连接的建立只要在监听到第一次握手的时候,控制系统伪造服务器发起第二次握手回应,就能阻断客户端与服务器连接的建立。因为我们的系统在内网,发出的报文肯定比服务器快,这样客户端接收到我们伪造的报文以后会回应第三次握手,当服务器真正的报文到达的时候客户端将不再处理,此时客户端再向服务器请求数据,因为seq号和ack号出错,服务器不会受理客户端的请求。

    

[cpp]  view plain copy
 
  1. typedef struct tcp_header {  
  2.     u_int16_t   th_sport;       /* source port */  
  3.     u_int16_t   th_dport;       /* destination port */  
  4.     tcp_seq     th_seq;         /* sequence number */  
  5.     tcp_seq     th_ack;         /* acknowledgement number */  
  6.     u_int8_t    th_offx2;       /* data offset, rsvd */  
  7. #define TH_OFF(th)  (((th)->th_offx2 & 0xf0) >> 4)  
  8.     u_int8_t    th_flags;  
  9. #define TH_FIN  0x01  
  10. #define TH_SYN  0x02  
  11. #define TH_RST  0x04  
  12. #define TH_PUSH 0x08  
  13. #define TH_ACK  0x10  
  14. #define TH_URG  0x20  
  15. #define TH_ECNECHO  0x40    /* ECN Echo */  
  16. #define TH_CWR      0x80    /* ECN Cwnd Reduced */  
  17.     u_int16_t   th_win;         /* window */  
  18.     u_int16_t   th_sum;         /* checksum */  
  19.     u_int16_t   th_urp;         /* urgent pointer */  
  20. }tcp_header;  

 

 

    判断第一次握手的方式flag = tcp_h->th_flags;当flag等于0x02的时候说明客户端发起tcp握手,伪装第二次握手的代码:

  

[cpp]  view plain copy
 
  1. int ForgedSYN(char *srcIP, char *dstIP, int srcPort, int dstPort)  
  2. {  
  3.     unsigned char buff[2048] = {0};  
  4.     unsigned char *ptr = buff;  
  5.     char options[4] = {0x02, 0x04, 0x05, 0x64};  
  6.     ip_header iph;  
  7.     tcp_header tcph;  
  8.     psd_header psdh;  
  9.     int num = 0;  
  10.     unsigned int isrcip;  
  11.     unsigned int idstip;  
  12.     unsigned short iIPSize = sizeof(ip_header) / sizeof(unsigned long);  
  13.     unsigned short iIPVersion = 4;  
  14.     unsigned short iTotalSize = sizeof(ip_header) + sizeof(tcp_header) + 4;  
  15.     unsigned short iTcpSize = sizeof(tcp_header) + 4;  
  16.     struct sockaddr_in server;  
  17.       
  18.     if(createSocket()<0) return -1;  
  19.       
  20.     iph.ip_vhl = (iIPVersion << 4) | iIPSize;  
  21.     iph.ip_tos = 0;  
  22.     iph.ip_len = htons(iTotalSize);  
  23.     iph.ip_id = htons(17393);  
  24.     iph.ip_off = 0;  
  25.     iph.ip_ttl = 118;  
  26.     iph.ip_p = IPPROTO_TCP;  
  27.     iph.ip_sum = 0;  
  28.     isrcip = inet_addr(srcIP);  
  29.     idstip = inet_addr(dstIP);  
  30.     memcpy(&iph.ip_src, &isrcip, 4);  
  31.     memcpy(&iph.ip_dst, &idstip, 4);  
  32.     iph.ip_sum = checksum((unsigned short *)&iph, 20);  
  33.   
  34.     tcph.th_sport = htons(srcPort);  
  35.     tcph.th_dport = htons(dstPort);  
  36.     tcph.th_seq = htonl(0x581A784D);  
  37.     tcph.th_ack = htonl(g_seq+1);  
  38.     tcph.th_offx2 = (24/4<<4|0);  
  39.     tcph.th_flags = 0x12;  
  40.     tcph.th_win = htons(16384);  
  41.     tcph.th_sum = 0;  
  42.     tcph.th_urp = 0;  
  43.   
  44.     psdh.s_addr = isrcip;  
  45.     psdh.d_addr = idstip;  
  46.     psdh.mbz = 0;  
  47.     psdh.protocol = IPPROTO_TCP;  
  48.     psdh.tcpl = htons(iTcpSize);  
  49.    
  50.     memcpy(buff, &psdh, sizeof(psd_header));  
  51.     memcpy(buff+sizeof(psd_header), &tcph, sizeof(tcp_header));  
  52.     memcpy(buff+sizeof(psd_header)+sizeof(tcp_header), options, 4);  
  53.     tcph.th_sum = checksum((unsigned short *)buff, sizeof(psd_header)+sizeof(tcp_header)+4);  
  54.   
  55.     memset(buff, 0x00, 2048);  
  56.     ptr = buff;  
  57.     memcpy(ptr, &iph, sizeof(ip_header));  
  58.     ptr += sizeof(ip_header);  
  59.     memcpy(ptr, &tcph, sizeof(tcp_header));  
  60.     ptr += sizeof(tcp_header);  
  61.     memcpy(ptr, options, 4);  
  62.   
  63.     server.sin_family = AF_INET;  
  64.     server.sin_port = htons(dstPort);  
  65.     server.sin_addr.s_addr = inet_addr(dstIP);  
  66.       
  67.     num = sendto(sockfd, buff, iTotalSize, 0, (struct sockaddr *)&server, sizeof(struct sockaddr));  
  68.   
  69.     return num;  
  70. }  

 

  数据伪造的时候ip头部和tcp头部要进行校验:

 

  

[cpp]  view plain copy
 
  1. unsigned short checksum(unsigned short *buffer, int size)  
  2. {  
  3.     unsigned long cksum=0;  
  4.    
  5.     while (size > 1)  
  6.     {  
  7.         cksum += *buffer++;  
  8.         size  -= sizeof(unsigned short);    
  9.     }  
  10.     if (size)  
  11.     {  
  12.         cksum += *(unsigned char *)buffer;    
  13.     }  
  14.     cksum = (cksum >> 16) + (cksum & 0xffff);  
  15.     cksum += (cksum >>16);  
  16.    
  17.     return (unsigned short)(~cksum);  
  18. }  

 

 

二、阻断已经建立起来的连接

      对于已经建立起来的连接只要伪造服务器发送rst包迫使客户端重新进行连接,或者fin包直接中断连接。

      正常通行中的tcp报文seq和ack存在如下关系,假设C向S请求数据,seq是seq1,ack是ack1,服务器返回给客户端的seq2和ack2必须存在这种关系:

      seq2 = ack1

      ack2 = seq1+datalen(服务返回报文的长度,不包括ip头和tcp头)

你可能感兴趣的:(协议分析之TCP旁路阻断)