📚 网络安全Kali学习系列 · 模块0-4 编程基础
已完成:模块0-1 Linux系统深度(6篇) ✅ | 模块0-2 计算机网络(4篇) ✅ | 模块0-3 密码学基础(3篇) ✅
14 Python安全编程:socket编程与端口扫描器(当前篇)
15 Bash脚本与安全自动化:工具链与日志解析
16 PHP基础与Web漏洞:危险函数与代码审计
17 JavaScript与前端安全:DOM操作与XSS

Python安全编程:socket编程与端口扫描器

难度:入门 | 模块0-2 你学了 TCP 三次握手,现在用 Python 亲手敲开每一扇端口,把网络理论变成可运行的安全工具
读完本篇你将能:用 socket 库建立 TCP 连接并抓取服务 Banner,用 ThreadPoolExecutor 编写多线程端口扫描器,用 argparse 为工具添加命令行参数——这是你在模块 1 学习 nmap 之前,理解端口扫描底层原理的最佳实践。
📑 本文目录
01Python与安全编程:为什么安全工程师首选Python
02socket库入门:TCP连接与Banner抓取
03单线程端口扫描器:从原理到实现
04多线程扫描器:ThreadPoolExecutor实战
05综合实战:带参数的完整端口扫描器
06安全红线与练习

01 Python与安全编程:为什么安全工程师首选Python

回顾模块 0-2,你用 Wireshark 抓包分析了 TCP 三次握手。但安全工程师不能只当旁观者——你需要用代码主动探测网络、验证漏洞、构建自动化工具。Python 是安全领域最常用的编程语言,原因有三:标准库自带 socket 网络库和 threading 并发库,无需安装任何依赖就能编写网络工具;语法简洁,10 行代码就能完成 C 语言 50 行的工作;生态丰富,Scapy(数据包构造)、Requests(HTTP 请求)、Paramiko(SSH)等库覆盖了安全测试的各个环节。

Python 当前稳定版本为 3.14(2025 年 10 月发布,截至 2026 年 8 月最新维护版本 3.14.7)。Kali Linux 默认预装 Python 3,打开终端输入 python3 --version 即可确认。本篇使用的 socket、threading、argparse、json 全部是标准库,在任何安装了 Python 3 的机器上都能直接运行。

库/模块 用途 标准库
socket TCP/UDP 网络通信 是
threading 多线程并发 是
argparse 命令行参数解析 是
scapy 数据包构造与嗅探 否(pip install scapy)
requests HTTP 请求 否(pip install requests)

本篇从标准库 socket 入手,这是所有 Python 网络编程的基石。掌握了 socket,你就理解了 nmap、Masscan 等专业扫描工具的底层逻辑——它们只是把同样的原理做得更快、更隐蔽。

02 socket库入门:TCP连接与Banner抓取

模块 0-2 你学了 TCP 三次握手:客户端发 SYN,服务端回 SYN-ACK,客户端再发 ACK,连接建立。Python 的 socket 库把这三步封装成一个 connect() 调用。端口扫描的本质就是向目标端口发起 TCP 连接:连接成功说明端口开放,连接被拒绝说明端口关闭。

先写一段最简单的代码:检测本地 80 端口是否开放。你可以把 127.0.0.1 换成你自己搭建的靶场 IP。

Python
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(3)
if sock.connect_ex(("127.0.0.1", 80)) == 0:
    print("端口 80 开放")
sock.close()

代码中有两个关键细节。第一,connect_ex() 是 connect() 的"安静版"——连接失败时返回错误码而非抛出异常,方便批量检测。返回 0 表示连接成功(端口开放),非 0 表示失败(端口关闭或被过滤)。第二,settimeout(3) 设置 3 秒超时,防止连接目标无响应时程序永久卡死。

端口开放只是第一步。安全工程师更关心端口上跑的是什么服务。很多服务在 TCP 连接建立后会主动发送欢迎信息(Banner),读取这段信息就能识别服务类型和版本——这个过程叫 Banner 抓取。

Python
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(3)
sock.connect(("127.0.0.1", 22))
banner = sock.recv(1024)
print(f"服务标识: {banner.decode().strip()}")
sock.close()

连接本地 22 端口(SSH),你会看到类似 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5 的输出。这个 Banner 暴露了 SSH 版本号和操作系统信息——对防御方来说是信息泄露,对攻击方来说是漏洞利用的切入点。后续模块 1 学习 nmap 的 -sV 参数时,你会发现它底层做的就是这件事,只不过更全面、更智能。

💡 小贴士
生产环境中,很多服务不再主动发送 Banner(如配置了 sshd_config 中的 Banner none)。此时需要主动发送探测数据(如 HTTP 请求)再读取响应。nmap 的服务指纹库(nmap-service-probes)收录了数百种探测规则,这就是专业工具比手写脚本强大的地方。

03 单线程端口扫描器:从原理到实现

你已经能检测单个端口了。安全评估通常需要扫描几十甚至上百个端口,把单端口检测放进循环就得到了端口扫描器。下面的代码扫描本机的 6 个常见端口:

Python
1
2
3
4
5
6
7
8
9
10
11
import socket
target = "127.0.0.1"
ports = [21, 22, 80, 443, 3306, 8080]
for port in ports:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(1)
    if sock.connect_ex((target, port)) == 0:
        print(f"[+] 端口 {port} 开放")
    sock.close()

运行后输出类似:

输出
[+] 端口 22 开放
[+] 端口 80 开放

代码逻辑清晰,但有个致命问题:速度太慢。每个端口最多等待 1 秒超时,扫描 6 个端口最多需要 6 秒。如果扫描 1-1024 号端口,最坏情况需要 1024 秒(约 17 分钟)。原因在于单线程串行执行——前一个端口扫描完才开始下一个。这就像逐个敲门,每扇门没人应答要等满 1 秒才去敲下一扇。

端口 服务 安全关注点
22 SSH 弱口令、旧版本漏洞
80 / 443 HTTP / HTTPS Web 漏洞(模块 2 重点)
3306 MySQL 未授权访问、弱口令
3389 RDP BlueKeep 漏洞、弱口令
8080 HTTP Proxy / Alt 管理后台暴露
⚠️ 常见错误
忘记调用 sock.close() — 每次循环创建新 socket 但不关闭,文件描述符很快耗尽,程序报 OSError: [Errno 24] Too many open files
✓ 正确:每次扫描完毕立即 sock.close(),或使用 with 上下文管理器自动释放

04 多线程扫描器:ThreadPoolExecutor实战

解决单线程慢的办法是并发:同时"敲门"100 扇。Python 有两种多线程方案。threading.Thread 需要手动创建线程、管理生命周期、处理共享变量的线程安全,代码复杂。concurrent.futures.ThreadPoolExecutor 是 Python 3.2+ 引入的高层封装,自动管理线程池和结果收集,是当前推荐的做法。

特性 threading.Thread ThreadPoolExecutor
线程池管理 手动创建、启动、join 自动管理,with 语句自动清理
结果获取 共享 list + Lock Future.result() 直接返回
线程数量控制 需自己限制 max_workers 参数直接设定
推荐度 学习理解用 生产环境首选

下面用 ThreadPoolExecutor 重写扫描器,同时扫描 1-1024 号端口:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket
from concurrent.futures import ThreadPoolExecutor, as_completed
def scan_port(target, port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(1)
    result = sock.connect_ex((target, port))
    sock.close()
    return port if result == 0 else None
target = "127.0.0.1"
with ThreadPoolExecutor(max_workers=100) as executor:
    futures = [executor.submit(scan_port, target, p)
                 for p in range(1, 1025)]
    for future in as_completed(futures):
        port = future.result()
        if port:
            print(f"[+] 端口 {port} 开放")

关键变化:max_workers=100 表示线程池最多同时运行 100 个线程。executor.submit() 把扫描任务提交到线程池,返回 Future 对象。as_completed() 按完成顺序(而非提交顺序)遍历结果,哪个端口先扫完就先输出。实测扫描 1024 个端口约需 1-2 秒,比单线程快了近 500 倍。

💡 小贴士
max_workers 并非越大越好。线程过多会导致系统上下文切换开销增大、socket 文件描述符耗尽。经验值:局域网扫描设 100-200,公网扫描设 50-100(公网延迟高,过多并发反而触发目标防火墙限速)。nmap 默认使用 SYN 半开扫描且能动态调节速率,这是它比 Python 脚本更高效的原因之一。

05 综合实战:带参数的完整端口扫描器

前面的代码每次运行都要修改源文件来更改目标 IP 和端口范围。真正的安全工具应该通过命令行参数接受输入——就像 nmap -p 1-1000 192.168.1.1 那样。Python 标准库的 argparse 模块就是为此而生。下面把前面学到的所有知识组装成一个完整的端口扫描器:

Python · scanner.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import socket, argparse, json
from concurrent.futures import ThreadPoolExecutor, as_completed
# 常见端口与服务映射
SERVICES = {21:"FTP", 22:"SSH", 80:"HTTP", 443:"HTTPS",
            3306:"MySQL", 3389:"RDP", 8080:"Proxy"}
def scan_port(target, port, timeout=1):
    """扫描单个端口"""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    result = sock.connect_ex((target, port))
    sock.close()
    if result == 0:
        return (port, SERVICES.get(port, "Unknown"))
    return None
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Python 端口扫描器")
    parser.add_argument("target", help="目标 IP 或域名")
    parser.add_argument("-p", "--ports", default="1-1024")
    parser.add_argument("-t", "--threads", type=int, default=100)
    parser.add_argument("-o", "--output", help="保存为 JSON")
    args = parser.parse_args()
    start, end = map(int, args.ports.split("-"))
    print(f"[*] 扫描 {args.target},端口 {args.ports}")
    open_ports = []
    with ThreadPoolExecutor(max_workers=args.threads) as executor:
        futures = [executor.submit(scan_port, args.target, p)
                     for p in range(start, end + 1)]
        for future in as_completed(futures):
            r = future.result()
            if r:
                open_ports.append(r)
                print(f"[+] {args.target}:{r[0]} - {r[1]}")
    print(f"[*] 完成,发现 {len(open_ports)} 个开放端口")
    if args.output:
        with open(args.output, "w") as f:
            json.dump(open_ports, f, indent=2)

保存为 scanner.py 后,使用方式如下:

Bash
# 基本用法:扫描 1-1024 端口,默认 100 线程
python3 scanner.py 127.0.0.1
# 指定端口范围和线程数
python3 scanner.py 192.168.1.1 -p 1-65535 -t 200
# 扫描结果保存为 JSON
python3 scanner.py 127.0.0.1 -p 1-1024 -o result.json

运行后输出示例:

输出
[*] 扫描 127.0.0.1,端口 1-1024
[+] 127.0.0.1:22 - SSH
[+] 127.0.0.1:80 - HTTP
[*] 完成,发现 2 个开放端口

代码逐段解读:SERVICES 字典映射常见端口号到服务名,扫描到开放端口时自动标注服务类型。argparse 定义了四个参数:target(必填,目标 IP)、-p(端口范围,默认 1-1024)、-t(线程数,默认 100)、-o(JSON 输出文件)。args.ports.split("-") 把 "1-1024" 拆成起止端口。-o 参数把结果存为 JSON,方便后续工具消费——在真实渗透测试中,扫描结果通常需要导入报告或传递给下一步工具。

⚠️ 常见错误
线程数设为 1000+ — 看似更快,实则触发操作系统文件描述符限制(默认 1024),大量 socket 创建失败,扫描结果不准
✓ 正确:先执行 ulimit -n 65535 提升限制,或将线程数控制在 200 以内

06 安全红线与练习

端口扫描是渗透测试的第一步,也是法律风险最高的一步。connect_ex() 发起的是完整的 TCP 三次握手,目标服务器的日志会记录你的 IP 地址和扫描行为。未经授权扫描他人网络违反《网络安全法》第 27 条和《刑法》第 285 条。合法的练习方式有三种:扫描 127.0.0.1(本机)、扫描自己搭建的虚拟机靶场(如 Metasploitable)、使用 scanme.nmap.org(Nmap 官方提供的合法扫描目标)。

⚖️ 法律红线
本篇代码仅用于学习目的。未经书面授权,禁止对任何非自有网络进行端口扫描。即使"只是看看端口开没开",在法律上也构成对计算机信息系统的探测行为。合法练习请使用本机、自建靶场或 scanme.nmap.org。
📖 知识回顾
socket库 connect_ex() settimeout() Banner抓取 ThreadPoolExecutor argparse TCP Connect Scan 多线程并发
✏️ 动手练习
🟢 基础验证
在本地启动一个服务(如 python3 -m http.server 8080),然后用本篇的 scanner.py 扫描 127.0.0.1 的 8080 端口,验证扫描器能正确发现该端口开放。
🟡 组合应用
修改 scanner.py,在发现开放端口后自动调用 Banner 抓取(对 HTTP 端口发送 b"GET / HTTP/1.0\r\n\r\n",对 SSH 端口直接 recv()),将 Banner 信息一并输出。提示:在 scan_port 函数中,连接成功后追加 recv 逻辑。
🔴 开放挑战
为 scanner.py 添加"SYN 半开扫描"模式。提示:标准 socket 库只能做完整连接扫描(TCP Connect Scan),SYN 扫描需要构造原始 IP 数据包。研究 Scapy 库的 sr1(IP(dst=target)/TCP(dport=port, flags="S")) 用法,对比两种扫描方式的隐蔽性差异。注意:SYN 扫描需要 root 权限。
下篇预告
15 Bash脚本与安全自动化:工具链与日志解析
将学习如何用 Bash 脚本拼接安全工具链,实现批量 nmap 扫描、日志解析与自动化报告生成——把零散命令组合成可复用的安全工作流
关注公众号 · 持续获取安全学习系列