Gre*_*der 5 python ip port tcp python-multithreading
我正在编写一个程序,需要扫描主机中的所有65535个端口,搜索那些打开的端口.这是我到目前为止,它的工作原理,但每次执行脚本时都会产生不同的结果,为什么会这样?
def check_open_port(host, port):
s = socket.socket()
s.settimeout(0.1)
# the SO_REUSEADDR flag tells the kernel to reuse a local
# socket in TIME_WAIT state, without waiting for its natural
# timeout to expire.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
code = s.connect_ex((host, port))
s.close()
if code == 0:
return True
else:
return False
except socket.error:
return False
def get_open_ports(host, max_port=65535):
open_ports = []
def worker(port):
if check_open_port(host, port):
open_ports.append(port)
pool = ThreadPoolExecutor(max_workers=10000)
[pool.submit(worker, port) for port in range(1, max_port + 1)]
pool.shutdown(wait=True)
return open_ports
Run Code Online (Sandbox Code Playgroud)
例如,在端口22,80和443打开的主机中,有时我得到此响应:
[22, 80]
有时我得到:
[22, 80, 443]
甚至:
[22]
具有更多开放端口的主机产生更多组合.
我玩过max_workers和玩过settimeout()价值观,但我无法让它运作良好.它唯一有效的时间是不使用线程,但显然需要很长时间才能完成,我需要使用它们.
我错过了什么吗?还有其他方法可以实现吗?
这里有2个问题:
我认为值得在此检查错误代码:
if code == 0:
return True
else:
return False
Run Code Online (Sandbox Code Playgroud)
鉴于你正试图运行一个池!10K线程可能会出现所有类型的错误 - 即达到某个系统/您的用户限制(检出ulimit -a),您可以将此类错误视为封闭端口而不另行通知.它可能解释您遇到的不稳定结果.
BTW在我的MacBook上结果是一致的(在VPS主机上查看我的实时服务器)
我也会选择更少数量的线程--10K是一种过度杀伤力.例如,以下是python 文档中建议的默认值:
在版本3.5中更改:如果max_workers为None或未给出,则默认为机器上的处理器数量,乘以5,假设ThreadPoolExecutor经常用于重叠I/O而不是CPU工作,并且工作者数量应该高于ProcessPoolExecutor的工作者数量
首先,没有必要使用threads/processes- 非阻塞套接字+ 像epoll这样的事件多路复用器已存在多年,所以你可以在没有额外线程/处理的情况下逃脱.
连接/关闭的方法也不是最理想的,因为您只需要检查端口是否打开 - 这里不需要全连接TCP连接.
在最简单的情况下,您只需发送一个SYN段并检查服务器将响应什么.
Scapy是一个功能强大的交互式数据包操作程序.它能够伪造或解码大量协议的数据包,通过线路发送,捕获它们,匹配请求和回复等等.它可以轻松处理大多数经典任务,如扫描,跟踪路由,探测,单元测试,攻击或网络发现(它可以取代hping,85%的nmap,arpspoof,arp-sk,arping,tcpdump,tethereal,p0f等).
这是方法描述之一(" TCP连接扫描 "):
客户端使用SYN标志和端口发送第一次握手,以连接到TCP数据包中的服务器.如果服务器使用RST而不是SYN-ACK进行响应,则在服务器上关闭该特定端口
还有一种方法(" TCP隐形扫描 "):
此技术类似于TCP连接扫描.客户端发送一个TCP数据包,其中设置了SYN标志和要连接的端口号.如果端口打开,则服务器使用TCP数据包内的SYN和ACK标志进行响应.但是这次客户端在TCP数据包中发送RST标志而不是RST + ACK,这是TCP连接扫描中的情况.此技术用于避免防火墙检测端口扫描
当然,如果只想玩套接字/线程,你的方法即使没有pcap/scapy也会很好
我在jupyter笔记本上尝试了你的代码,我总是得到相同的端口集:
get_open_ports('127.0.0.1')
Run Code Online (Sandbox Code Playgroud)
输出:
[133, 200, 144...60700]
是否有可能在特定时间打开不同数量的端口以供查询主机?
为了验证一小组端口,我减少max_port了10000,每次仍然得到相同的端口集:
def get_open_ports(host, max_port=10000):
open_ports = []
def worker(port):
if check_open_port(host, port):
open_ports.append(port)
with ThreadPoolExecutor(max_workers=10000) as executor:
[executor.submit(worker, port) for port in range(1, max_port + 1)]
executor.shutdown(wait=True)
return open_ports
get_open_ports('127.0.0.1')
Run Code Online (Sandbox Code Playgroud)
输出: [150, 900, 1035, 7789]
注意:出于安全考虑,我更改了端口号.
编辑:
def get_open_ports(host, max_port=65535):
open_ports = []
def worker(port):
if check_open_port(host, port):
open_ports.append(port)
# We can use a with statement to ensure threads are cleaned up promptly
with ThreadPoolExecutor(max_workers=100) as executor:
print('main:starting')
wait_for=[executor.submit(worker,port) for port in range(1, max_port + 1)]
for f in as_completed(wait_for):
print('main: result: {}'.format(f.result())) #check result on each thread execution
# executor.shutdown(wait=True) #not required when using the 'with' statement
return len(open_ports)
test = get_open_ports('45.60.112.163') #hostname for www.indracompany.com
#max_workers not defined & max_port=10000
# len(test) #test1: 148
# len(test) #test 2: 79
#max_workers = 10000 & max_port=65535
# len(test) #test1: 1
# len(test) #test2:1
# len(test) #test3:1
#max_workers = 20000 & max_port=65535
# len(test) #test1: 14
# len(test) #test2:1
# len(test) #test3: 1
# len(test) #test4:1
#max_workers not defined & max_port=65535 #quite time-consuming
# len(test) #test1: 63
Run Code Online (Sandbox Code Playgroud)
编辑2:更可靠的解决方案
正如@Tarun所建议的那样,Python的python-nmap库在扫描主机方面做得更好.
以下解决方案给出了准确的结果,但是,随着端口发现范围的增加,我观察到了性能上的重大折衷.也许,线程可以合并到代码中以提高性能.我还导入了时间库以最终获得程序执行时间.在测试性能时,这可用于比较目的.
# The python-nmap library helps to programmatically manipulate scanned results of nmap to automate port scanning tasks.
# To use this library you must have the Nmap software installed. This can be installed from https://nmap.org/download.html.
# Network Mapper (Nmap) is a free and open-source tool used for network discovery and security auditing.
# It runs on all major computer operating systems, and official binary packages are available for Linux, Windows, and Mac OS X.
# For Windows 7 and later, you must also upgrade 'NCap' from https://nmap.org/npcap/
# For Windows, make sure nmap.exe is added to PATH.
# When you're ready, pip install python-nmap
import time
import nmap
nm = nmap.PortScanner() #initialize PortScanner object
host = '45.60.112.163' #specify host
nm.scan(host, '1-100') #run the scan, specify host and range of ports to scan
#Optional steps for verification:
#Output: nmap -oX - -p 1-100 -sV 45.60.112.163
print(nm.command_line()) #command_line command to execute on nmap command prompt
#Output: {'tcp': {'method': 'syn', 'services': '1-100'}}
print(nm.scaninfo()) #nmap scan information
#Now we can scan all hosts
#From Official documentation at https://xael.org/pages/python-nmap-en.html
start_time = time.time() #To get program execution time
for host in nm.all_hosts():
print('----------------------------------------------------')
print('Host : %s (%s)' % (host, nm[host].hostname()))
print('State : %s' % nm[host].state())
for proto in nm[host].all_protocols():
print('----------')
print('Protocol : %s' % proto)
lport = nm[host][proto].keys()
for key in sorted(lport):
for port in lport:
print ('port : %s\tstate : %s' % (port, nm[host][proto][port]['state']))
print('Execution time: %s seconds' % (time.time() - start_time))
#Output:
----------------------------------------------------
Host : 45.60.112.163 ()
State : up
----------
Protocol : tcp
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
port : 25 state : open
port : 51 state : open
port : 53 state : open
port : 80 state : open
port : 81 state : open
port : 85 state : open
port : 91 state : open
Execution time: 0.015624761581420898 seconds
Run Code Online (Sandbox Code Playgroud)
要将输出转换为csv,请使用:
print(nm.csv())
Run Code Online (Sandbox Code Playgroud)
经过这次调查,Nmap现已安装在我的计算机上.为了好玩,我还使用下面的命令在命令提示符上运行扫描.这次扫描的范围是"1-1000",耗时超过15分钟(我没有参加整个会议!).