我正试图使一个端口扫描仪,但由于我的条件,它非常缓慢和无效



细节是,我相信有很多事情在我的for循环中进行,我想知道是否有一个更有效的方法来完成这个任务

我希望使用大量的if/elif语句将端口映射到服务,但它很慢。如何将端口映射到for循环之外的服务以获得更快的速度

import socket
import pyfiglet
from colorama import Fore
ascii_banner = pyfiglet.figlet_format("Port Scanner")
print(ascii_banner)
remoteserver = input('please enter your target:')
remoteserverIP = socket.gethostbyname(remoteserver) # name resoultion
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
for port in range(1,22):
result = sock.connect_ex((remoteserverIP,port))
if result == 0:
result = port
print(f"{result} is open")
if result == 80:
print(' Service:http')
elif result == 21:
print('Service:ftp')
elif result == 22:
print('Service:ssh')
elif result == 23:
print('Service:telnet')
elif result == 554:
print('Service:RTSP')
elif result == 5432:
print('Service:PostgreSQL')
elif result == 3306:
print('Service:MySQL')

我只是将它们映射到格式为{ port: service, }的字典。您可以使用内置方法创建字典中的键列表,然后根据字典中是否存在端口映射来输出。

import socket
common_services = {
80: "Service:http",
21: "Service:ftp",
22: "Service:ssh",
12: "Service:telnet",
554: "Service:RTSP",
5432: "Service:PostgreSQL",
3306: "Service:MySQL",
}
known_ports = list(common_services.keys())
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
for port in range(1,22):
result = sock.connect_ex((ip,port))
if result == 0:
msg = f"{port} is open, {common_services[port]}" if port in known_ports else f"{port} is open"
print(msg)

添加@rzz的答案,他是正确的,服务可以在不同的端口上配置:您可以使用socket.getservbyport()函数从端口确定服务名称,而无需使用手工的if语句链。它不一定具有您想要的所有服务,因此您将希望捕获OSError并使用其他人建议的字典。

但是,我不确定您遇到的主要速度瓶颈是if语句的顺序。你这么说是因为你对应用程序进行了分析,还是仅仅是一种直觉?

最有可能的原因是您正在按顺序执行所有这些请求。您可能希望并发地触发尽可能多的请求,然后在它们到来时打印结果。或者,您可以将它们添加到一个结构中,并在最后按您希望的顺序打印它们。

你可以通过系统线程或者async/await来实现。我更喜欢第二种方法,因为基本上只有I/O限制,而且可以避免上下文切换的开销。

下面是一个工作示例:

import asyncio
import socket
async def scan(host, port, timeout, results):
try:
await asyncio.wait_for(asyncio.open_connection(host, port), timeout=timeout)
results[port] = "open"
except TimeoutError:
results[port] = "timeout"
except Exception as e:  # you will want to better catch this and differentiate accordingly
results[port] = str(e)

async def main():
hostname = 'www.google.com'
results = {}
ports = [21, 80, 554]
host = socket.gethostbyname(hostname)
await asyncio.gather(*[scan(host, port, 2, results) for port in ports])
for port in ports:
print(f"Port {port} of service {socket.getservbyport(port)} result: {results[port]}.")
asyncio.run(main())

要减少循环中if和else的数量,可以使用字典。

然而,在开发端口扫描程序时,有一点很重要,您需要记住,服务可以在不同的端口上配置。因此,端口可能不是对正在运行的服务的有效引用,从而使您的代码和结果/输出不那么一致。

您可以尝试返回服务的横幅,如:

s.recv(1024).decode()

套接字将返回1024字节的缓冲区大小的横幅,然后我们将其解码为字符串。您需要添加如下内容:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
banner = s.recv(1024).decode()

Ed1:添加对portscanner的引用和使用横幅的示例:reference

相关内容

最新更新