http://blog.csdn.net/pluton/article/details/5816227
一、阻断未建立起来的连接
我们知道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号出错,服务器不会受理客户端的请求。
- typedef struct tcp_header {
- u_int16_t th_sport;
- u_int16_t th_dport;
- tcp_seq th_seq;
- tcp_seq th_ack;
- u_int8_t th_offx2;
- #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;
- u_int16_t th_sum;
- u_int16_t th_urp;
- }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头)