我正在编写一个程序,需要扫描主机中的所有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
例如,在端口22,80和443打开的主机中,有时我得到此响应:
[22, 80]
有时我得到:
[22, 80, 443]
甚至:
[22]
具有更多开放端口的主机产生更多组合。
我玩过max_workers
和settimeout()
值,但我无法让它运作良好。它唯一有效的时间是不使用线程,但显然需要花费很长时间才能完成,我需要使用它们。
我错过了什么吗?还有其他方法可以实现吗?
答案 0 :(得分:7)
这里有2个问题:
我认为值得在此检查错误代码:
if code == 0:
return True
else:
return False
鉴于您正在尝试运行池! 10K 线程可能会出现所有类型的错误 - 即达到某个系统/您的用户限制(请查看ulimit -a
),您可以将此类错误视为封闭端口而不另行通知。它可能会解释您遇到的不稳定结果。
我也会选择较少数量的线程 - 10K 是一种过度杀伤力。例如,以下是python docs中建议的默认值:
在版本3.5中更改:如果max_workers为None或未给出,则会 默认为机器上的处理器数量,乘以5, 假设ThreadPoolExecutor经常用于重叠I / O. CPU工作量和工人数应高于数量 ProcessPoolExecutor的工作人员
首先,没有必要使用threads/processes
- 非阻塞套接字+事件multiplexors如epoll已存在多年,因此您可以在没有的情况下离开额外的线程/处理过的任何内容。
连接/关闭的方法也不是最理想的,因为您只需要检查端口是否打开 - 这里不需要全连接TCP连接。
在最简单的情况下,您只需发送 SYN 段并检查服务器将响应的内容。
的十几种方法Scapy是一个功能强大的交互式数据包操作程序。它是 能够伪造或解码大量协议的数据包,发送 他们在线上,捕获它们,匹配请求和回复等等 更多。它可以轻松处理大多数经典任务,如扫描, 跟踪路由,探测,单元测试,攻击或网络发现(它 可以取代hping,85%的nmap,arpspoof,arp-sk,arping,tcpdump, tethereal,p0f等。)。
以下是其中一种方法说明(“ TCP连接扫描”):
客户端使用SYN标志和端口发送第一次握手 连接到TCP数据包中的服务器。如果服务器响应a RST而不是SYN-ACK,然后该特定端口关闭 服务器
还有一种方法(“ TCP隐身扫描”):
此技术类似于TCP连接扫描。客户端发送一个 设置了SYN标志的TCP数据包和要连接的端口号。如果 端口打开,服务器响应SYN和ACK标志 在TCP数据包中。但这次客户端发送一个RST标志 TCP数据包而不是RST + ACK,这是TCP连接中的情况 扫描。该技术用于避免端口扫描检测 防火墙
当然如果只是想玩套接字/线程,你的方法即使没有pcap / scapy也会没问题
答案 1 :(得分:5)
我在jupyter笔记本上尝试了你的代码,我总是得到相同的端口集:
get_open_ports('127.0.0.1')
输出:
[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')
输出:[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
编辑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
要将输出转换为csv,请使用:
print(nm.csv())
通过此调查,Nmap现已安装在我的计算机上。为了好玩,我还使用下面的命令在命令提示符上运行扫描。此扫描范围为1-1000'花了超过15分钟(我没有参加整个会议!)。
答案 2 :(得分:1)
我在使用python中的套接字时遇到过这个端口扫描程序......
import socket
import threading
from queue import *
print_lock = threading.Lock()
target = input("Enter websit or IP Adress to scan: ")
minPort = int(input("Enter minimum Port to scan (1 is the smallest): "))
maxPort = int(input("Enter maximum Port to scan: "))
threadNo = int(input("Enter No. of threads to use(500 is a good all around number): "))
def portscan(port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
con = s.connect((target, port))
with print_lock:
print("Port", port, "is open!")
con.close()
except:
pass
def threader():
while True:
worker = q.get()
portscan(worker)
q.task_done()
q = Queue()
for x in range(threadNo):
t = threading.Thread(target=threader)
t.daemon = True
t.start()
for worker in range (minPort, maxPort):
q.put(worker)
q.join()
它运作良好,可以轻松调整:)