協議分析之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號出錯,伺服器不會受理客戶端的請求。
- typedefstruct tcp_header {
- u_int16_t th_sport; /* source port */
- u_int16_t th_dport; /* destination port */
- tcp_seq th_seq; /* sequence number */
- tcp_seq th_ack; /* acknowledgement number */
- u_int8_t th_offx2; /* data offset, rsvd */
- #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
- u_int8_t th_flags;
- #define TH_FIN 0x01
- #define TH_SYN 0x02
- #define TH_RST 0x04
- #define TH_PUSH 0x08
- #define TH_ACK 0x10
- #define TH_URG 0x20
- #define TH_ECNECHO 0x40 /* ECN Echo */
- #define TH_CWR 0x80 /* ECN Cwnd Reduced */
- u_int16_t th_win; /* window */
- u_int16_t th_sum; /* checksum */
- u_int16_t th_urp; /* urgent pointer */
- }tcp_header;
判斷第一次握手的方式flag = tcp_h->th_flags;當flag等於0x02的時候說明客戶端發起tcp握手,偽裝第二次握手的程式碼:
- int ForgedSYN(char *srcIP, char *dstIP, int srcPort, int dstPort)
- {
- unsigned char buff[2048] = {0};
- unsigned char *ptr = buff;
- char options[4] = {0x02, 0x04, 0x05, 0x64};
- ip_header iph;
- tcp_header tcph;
- psd_header psdh;
- int num = 0;
- unsigned int isrcip;
- unsigned int idstip;
- unsigned short iIPSize = sizeof(ip_header) / sizeof(unsigned long);
- unsigned short iIPVersion = 4;
- unsigned short iTotalSize = sizeof(ip_header) + sizeof(tcp_header) + 4;
- unsigned short iTcpSize = sizeof(tcp_header) + 4;
- struct sockaddr_in server;
- if(createSocket()<0) return -1;
- iph.ip_vhl = (iIPVersion << 4) | iIPSize;
- iph.ip_tos = 0;
- iph.ip_len = htons(iTotalSize);
- iph.ip_id = htons(17393);
- iph.ip_off = 0;
- iph.ip_ttl = 118;
- iph.ip_p = IPPROTO_TCP;
- iph.ip_sum = 0;
- isrcip = inet_addr(srcIP);
- idstip = inet_addr(dstIP);
- memcpy(&iph.ip_src, &isrcip, 4);
- memcpy(&iph.ip_dst, &idstip, 4);
- iph.ip_sum = checksum((unsigned short *)&iph, 20);
- tcph.th_sport = htons(srcPort);
- tcph.th_dport = htons(dstPort);
- tcph.th_seq = htonl(0x581A784D);
- tcph.th_ack = htonl(g_seq+1);
- tcph.th_offx2 = (24/4<<4|0);
- tcph.th_flags = 0x12;
- tcph.th_win = htons(16384);
- tcph.th_sum = 0;
- tcph.th_urp = 0;
- psdh.s_addr = isrcip;
- psdh.d_addr = idstip;
- psdh.mbz = 0;
- psdh.protocol = IPPROTO_TCP;
- psdh.tcpl = htons(iTcpSize);
- memcpy(buff, &psdh, sizeof(psd_header));
- memcpy(buff+sizeof(psd_header), &tcph, sizeof(tcp_header));
- memcpy(buff+sizeof(psd_header)+sizeof(tcp_header), options, 4);
- tcph.th_sum = checksum((unsigned short *)buff, sizeof(psd_header)+sizeof(tcp_header)+4);
- memset(buff, 0x00, 2048);
- ptr = buff;
- memcpy(ptr, &iph, sizeof(ip_header));
- ptr += sizeof(ip_header);
- memcpy(ptr, &tcph, sizeof(tcp_header));
- ptr += sizeof(tcp_header);
- memcpy(ptr, options, 4);
- server.sin_family = AF_INET;
- server.sin_port = htons(dstPort);
- server.sin_addr.s_addr = inet_addr(dstIP);
- num = sendto(sockfd, buff, iTotalSize, 0, (struct sockaddr *)&server, sizeof(struct sockaddr));
- return num;
- }
資料偽造的時候ip頭部和tcp頭部要進行校驗:
- unsigned short checksum(unsigned short *buffer, int size)
- {
- unsigned long cksum=0;
- while (size > 1)
- {
- cksum += *buffer++;
- size -= sizeof(unsigned short);
- }
- if (size)
- {
- cksum += *(unsigned char *)buffer;
- }
- cksum = (cksum >> 16) + (cksum & 0xffff);
- cksum += (cksum >>16);
- return (unsigned short)(~cksum);
- }
二、阻斷已經建立起來的連線
對於已經建立起來的連線只要偽造伺服器傳送rst包迫使客戶端重新進行連線,或者fin包直接中斷連線。
正常通行中的tcp報文seq和ack存在如下關係,假設C向S請求資料,seq是seq1,ack是ack1,伺服器返回給客戶端的seq2和ack2必須存在這種關係:
seq2 = ack1
ack2 = seq1+datalen(服務返回報文的長度,不包括ip頭和tcp頭)