1. 程式人生 > >協議分析之TCP旁路阻斷

協議分析之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號出錯,伺服器不會受理客戶端的請求。

  1. typedefstruct 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握手,偽裝第二次握手的程式碼:

  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.     if(createSocket()<0) return -1;  
  18.     iph.ip_vhl = (iIPVersion << 4) | iIPSize;  
  19.     iph.ip_tos = 0;  
  20.     iph.ip_len = htons(iTotalSize);  
  21.     iph.ip_id = htons(17393);  
  22.     iph.ip_off = 0;  
  23.     iph.ip_ttl = 118;  
  24.     iph.ip_p = IPPROTO_TCP;  
  25.     iph.ip_sum = 0;  
  26.     isrcip = inet_addr(srcIP);  
  27.     idstip = inet_addr(dstIP);  
  28.     memcpy(&iph.ip_src, &isrcip, 4);  
  29.     memcpy(&iph.ip_dst, &idstip, 4);  
  30.     iph.ip_sum = checksum((unsigned short *)&iph, 20);  
  31.     tcph.th_sport = htons(srcPort);  
  32.     tcph.th_dport = htons(dstPort);  
  33.     tcph.th_seq = htonl(0x581A784D);  
  34.     tcph.th_ack = htonl(g_seq+1);  
  35.     tcph.th_offx2 = (24/4<<4|0);  
  36.     tcph.th_flags = 0x12;  
  37.     tcph.th_win = htons(16384);  
  38.     tcph.th_sum = 0;  
  39.     tcph.th_urp = 0;  
  40.     psdh.s_addr = isrcip;  
  41.     psdh.d_addr = idstip;  
  42.     psdh.mbz = 0;  
  43.     psdh.protocol = IPPROTO_TCP;  
  44.     psdh.tcpl = htons(iTcpSize);  
  45.     memcpy(buff, &psdh, sizeof(psd_header));  
  46.     memcpy(buff+sizeof(psd_header), &tcph, sizeof(tcp_header));  
  47.     memcpy(buff+sizeof(psd_header)+sizeof(tcp_header), options, 4);  
  48.     tcph.th_sum = checksum((unsigned short *)buff, sizeof(psd_header)+sizeof(tcp_header)+4);  
  49.     memset(buff, 0x00, 2048);  
  50.     ptr = buff;  
  51.     memcpy(ptr, &iph, sizeof(ip_header));  
  52.     ptr += sizeof(ip_header);  
  53.     memcpy(ptr, &tcph, sizeof(tcp_header));  
  54.     ptr += sizeof(tcp_header);  
  55.     memcpy(ptr, options, 4);  
  56.     server.sin_family = AF_INET;  
  57.     server.sin_port = htons(dstPort);  
  58.     server.sin_addr.s_addr = inet_addr(dstIP);  
  59.     num = sendto(sockfd, buff, iTotalSize, 0, (struct sockaddr *)&server, sizeof(struct sockaddr));  
  60.     return num;  
  61. }  

  資料偽造的時候ip頭部和tcp頭部要進行校驗:

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

二、阻斷已經建立起來的連線

      對於已經建立起來的連線只要偽造伺服器傳送rst包迫使客戶端重新進行連線,或者fin包直接中斷連線。

      正常通行中的tcp報文seq和ack存在如下關係,假設C向S請求資料,seq是seq1,ack是ack1,伺服器返回給客戶端的seq2和ack2必須存在這種關係:

      seq2 = ack1

      ack2 = seq1+datalen(服務返回報文的長度,不包括ip頭和tcp頭)