基于Scapy抓包确定TCP/IP连接的服务端口
嘿,这个问题我之前用Scapy分析陌生流量的时候也碰到过!除了你提到的连接发起方判断法,还有不少实用的技巧可以帮你区分服务端端口和客户端端口,下面我把这些方法整理出来,结合Scapy的使用场景给你细说:
基于TCP握手包的方向判断
TCP连接的三次握手是最核心的判断依据:客户端先发送纯SYN包(无ACK标记),服务端回复SYN+ACK,最后客户端发ACK确认。所以在抓包时,找到TCP.flags.SYN == 1 and TCP.flags.ACK == 0的包,这个包的目的端口就是服务端端口——因为客户端发起连接时,目标必然是服务端的监听端口。用Scapy可以这么实现:from scapy.all import sniff, TCP, IP def identify_service_port(pkt): if TCP in pkt and pkt[TCP].flags == 'S': # 匹配纯SYN包 print(f"疑似服务端口: {pkt[TCP].dport}") print(f"发起连接的客户端: {pkt[IP].src}:{pkt[TCP].sport}") sniff(prn=identify_service_port, filter="tcp", count=10)利用端口范围的动态/静态规律
客户端通常使用临时动态端口,IANA规定的动态端口范围是:- 传统区间:1024-49151
- 现代默认区间:49152-65535(多数操作系统用这个)
而服务端端口哪怕不是知名端口(1-1023),也大概率落在1-49151的注册/静态端口区间。如果两个端口一个在49152以上,另一个在更低区间,那低区间的端口基本就是服务端口。
统计流量的发起频率与指向性
服务端端口是持续监听的,所以你会看到多个不同客户端IP向同一个目的端口发起连接;而客户端端口是临时的,每个客户端的源端口只会对应单个连接,不会有大量外部IP主动向它发起请求。用Scapy统计端口的访问来源数量,就能快速定位:比如统计所有TCP包中,每个dst_port对应的不同srcIP数量,数量最多的那个就是服务端口。结合主机本地监听端口验证(若有权限)
如果你能登录抓包主机或目标主机,直接用系统命令查看正在监听的端口,就能100%确认:- Linux/macOS:
netstat -tulpn或ss -tulpn,找LISTEN状态的端口 - Windows:
netstat -ano | findstr LISTENING,对应端口就是服务端正在监听的端口
把这个结果和抓包数据对比,就能直接对应上未知端口的身份。
- Linux/macOS:
解析应用层协议特征辅助判断
很多应用层协议有独特的标识,哪怕端口未知,也能通过 payload 内容判断。比如HTTP的GET/POST请求行、SSH的SSH-版本字符串、DNS的报文格式等。用Scapy解析应用层数据就能识别:def check_app_protocol(pkt): if TCP in pkt and pkt[TCP].payload: payload_str = str(pkt[TCP].payload) if "HTTP/" in payload_str: # 客户端发请求,服务端回响应,所以含GET的是客户端发的,对应目的端口是服务端口 service_port = pkt[TCP].dport if "GET " in payload_str else pkt[TCP].sport print(f"HTTP服务端口: {service_port}") elif payload_str.startswith("SSH-"): # SSH服务端会先返回版本字符串,所以对应端口是服务端口 print(f"SSH服务端口: {pkt[TCP].sport}") sniff(prn=check_app_protocol, filter="tcp", count=20)
这些方法组合起来用,基本就能准确判断出服务端口了。我自己常用的流程是先看SYN包方向,再结合端口范围和流量频率,大部分场景都能快速搞定。
内容的提问来源于stack exchange,提问作者NikaTsanka

