用 Python 构建端口扫描器

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本项目中,我们将使用Python开发一个服务器端口扫描器,以检测目标服务器上的开放端口。此工具对于系统管理员(用于验证安全策略)和潜在攻击者(用于识别主机上运行的网络服务)都至关重要。我们的探索将涵盖端口扫描的基本方面,包括其方法和影响。我们将深入研究如何利用Python的功能创建一个简单而有效的端口扫描器,重点是采用多线程方法来提高效率和性能。

端口扫描是向一系列服务器端口发送请求以确定哪些端口开放的过程。此步骤对于维护安全性以及攻击者查找易受攻击的服务都至关重要。我们将从探索端口扫描的基础知识及其影响开始。

关键概念:

  • 端口扫描器有助于检测服务器或主机上的开放端口。
  • 它们用于安全评估,攻击者也用其识别易受攻击的服务。
  • 最简单的端口扫描形式涉及尝试与一系列端口建立TCP连接。

👀 预览

以下是我们将要构建的端口扫描器工具的抢先看:

python port_scanner.py 127.0.0.1 5000-9000

输出:

已开放端口:8081
扫描完成。

🎯 任务

在本项目中,你将学习:

  • 如何利用Python的套接字编程功能与网络端口进行交互。
  • 如何在Python中实现多线程方法以提高网络扫描任务的效率。
  • 如何在Python中开发一个命令行工具,该工具接受用户输入以进行灵活的端口扫描。

🏆 成果

完成本项目后,你将能够:

  • 使用Python的套接字库创建网络连接、测试端口可用性并处理网络异常。
  • 理解并应用Python中的多线程来执行并发任务,显著提高网络密集型操作的性能。
  • 构建一个实用的命令行端口扫描器工具,提升你的Python脚本技能以及对命令行参数解析的理解。

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python(("Python")) -.-> python/NetworkingGroup(["Networking"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/arguments_return("Arguments and Return Values") python/FunctionsGroup -.-> python/build_in_functions("Build-in Functions") python/ModulesandPackagesGroup -.-> python/standard_libraries("Common Standard Libraries") python/FileHandlingGroup -.-> python/with_statement("Using with Statement") python/AdvancedTopicsGroup -.-> python/threading_multiprocessing("Multithreading and Multiprocessing") python/NetworkingGroup -.-> python/socket_programming("Socket Programming") subgraph Lab Skills python/function_definition -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/arguments_return -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/build_in_functions -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/standard_libraries -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/with_statement -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/threading_multiprocessing -.-> lab-415965{{"用 Python 构建端口扫描器"}} python/socket_programming -.-> lab-415965{{"用 Python 构建端口扫描器"}} end

建立TCP连接测试

我们的第一步是编写一个函数来测试目标IP上的TCP端口是否开放。这个函数将尝试连接到指定端口并确定其状态。

/home/labex/project目录下打开名为port_scanner.py的文件,并添加以下Python函数:

import argparse
from queue import Queue
from socket import AF_INET, gethostbyname, socket, SOCK_STREAM
import threading

def tcp_test(port: int, target_ip: str) -> None:
    with socket(AF_INET, SOCK_STREAM) as sock:
        sock.settimeout(1)
        result = sock.connect_ex((target_ip, port))
        if result == 0:
            print(f"Opened Port: {port}")

这段代码定义了一个名为tcp_test的函数,该函数尝试在目标IP地址上建立到指定端口的TCP连接。它设置了一个超时时间以避免在每个端口上长时间等待,并使用connect_ex来尝试连接。

如果connect_ex返回0,则表示连接成功,即端口开放,该函数会打印一条消息指示开放的端口。

✨ 查看解决方案并练习

设置并发端口检查

接下来,我们将创建一个worker函数,每个线程将使用该函数从队列中处理端口,并利用tcp_test函数检查每个端口的状态。

将以下代码添加到你的port_scanner.py中:

def worker(target_ip: str, queue: Queue) -> None:
    while not queue.empty():
        port = queue.get()
        tcp_test(port, target_ip)
        queue.task_done()

worker函数设计为由多个线程运行。它不断从队列中获取端口号,并使用之前定义的tcp_test函数检查这些端口在目标IP上是否开放。

测试完一个端口后,它会在队列中将任务标记为已完成。此函数允许并发扫描端口,显著加快扫描过程。

✨ 查看解决方案并练习

协调扫描过程

main函数通过设置队列、初始化工作线程以及管理指定端口范围内的扫描操作来协调扫描过程。

继续在你的port_scanner.py中添加main函数:

def main(host: str, start_port: int, end_port: int) -> None:
    target_ip = gethostbyname(host)
    queue = Queue()
    for port in range(start_port, end_port + 1):
        queue.put(port)
    for _ in range(100):  ## 根据需要调整线程数量
        t = threading.Thread(target=worker, args=(target_ip, queue,))
        t.daemon = True
        t.start()
    queue.join()
    print("Scanning completed.")

main函数协调整个端口扫描过程。

它首先将目标主机名解析为IP地址,然后为要扫描的端口号创建一个队列。它用指定范围内的所有端口填充队列,并生成多个工作线程(在这个例子中是100个),这些线程通过检查每个端口来并发处理队列。该函数等待所有端口都被处理完(queue.join()),然后打印一条消息表示扫描已完成。

✨ 查看解决方案并练习

运行端口扫描器

最后,是时候运行我们的端口扫描器了。我们将扫描本地主机上的一系列端口来测试我们的工具。

在你的port_scanner.py末尾添加以下几行代码,使脚本可执行:

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='TCP Port Scanner')
    parser.add_argument('host', help='Host to scan')
    parser.add_argument('ports', help='Port range to scan, formatted as start-end')
    args = parser.parse_args()

    start_port, end_port = map(int, args.ports.split('-'))
    main(args.host, start_port, end_port)

这段代码使用命令行参数解析来使端口扫描器脚本更通用且用户友好。

通过使用argparse库,它定义了两个必需参数:hostports

  • host参数用于指定你想要扫描的目标主机的地址或主机名。
  • ports参数期望一个字符串,该字符串定义要扫描的端口范围,格式为“起始端口-结束端口”(例如,“5000-8000”),脚本通过使用-分隔符将其拆分为start_portend_port,然后将它们转换为整数。这允许用户在从命令行运行脚本时轻松指定目标和端口范围。

现在,在终端中运行以下命令来执行扫描器:

python port_scanner.py 127.0.0.1 5000-9000

输出:

已开放端口:8081
扫描完成。

现在你已经使用端口扫描器识别出一个开放端口(8081),并且有一个Web服务器在该端口上运行,你可以探索那里托管的内容。

要做到这一点,首先点击添加按钮并选择“Web服务”选项。

选择Web服务选项

然后输入端口8081并点击“访问”按钮。

输入端口并访问Web服务器

你会发现在你的系统中Web服务器正在运行,监听端口8081。

Web服务器在端口8081上运行
✨ 查看解决方案并练习

总结

在这个项目中,我们用Python构建了一个基本的端口扫描器,从基础的tcp_test函数到多线程扫描方法。我们将这个过程分解为可管理的步骤,最终得到一个能够识别目标服务器上开放端口的实用工具。通过这次实践经验,我们不仅加深了对网络安全的理解,还磨练了Python编程和并发管理技能。