一、阻断未建立起来的连接
我们知道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. typedef struct tcp_header {
2. /* source port */
3. /* destination port */
4. /* sequence number */
5. /* acknowledgement number */
6. /* 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. /* window */
18. /* checksum */
19. /* 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. char buff[2048] = {0};
4. 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. int isrcip;
11. int idstip;
12. short iIPSize = sizeof(ip_header) / sizeof(unsigned long);
13. short iIPVersion = 4;
14. short iTotalSize = sizeof(ip_header) + sizeof(tcp_header) + 4;
15. 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. 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. sizeof(psd_header));
51. sizeof(psd_header), &tcph, sizeof(tcp_header));
52. sizeof(psd_header)+sizeof(tcp_header), options, 4);
53. short *)buff, sizeof(psd_header)+sizeof(tcp_header)+4);
54.
55. memset(buff, 0x00, 2048);
56. ptr = buff;
57. sizeof(ip_header));
58. sizeof(ip_header);
59. sizeof(tcp_header));
60. 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. struct sockaddr *)&server, sizeof(struct sockaddr));
68.
69. return num;
70. }
数据伪造的时候ip头部和tcp头部要进行校验:
1. unsigned short checksum(unsigned short *buffer, int size)
2. {
3. long cksum=0;
4.
5. while (size > 1)
6. {
7. cksum += *buffer++;
8. sizeof(unsigned short);
9. }
10. if (size)
11. {
12. 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头)