Scapy提取pcap密码套件时仅取每个文件首个匹配数据包
Scapy提取pcap中首个匹配包的TLS密码套件实现
需求说明
使用Scapy从pcap文件中提取TLS密码套件,按照预设过滤规则,仅需返回每个pcap文件中第一个符合筛选条件的数据包对应的密码套件结果。
原有实现代码
from scapy.all import * from scapy.layers.radius import Radius import re import os import pathlib def get_ciphersuite(): ciphersuites = { #'0000' : 'TLS_NULL_WITH_NULL_NULL', '002f' : 'TLS_RSA_WITH_AES_128_CBC_SHA', '0035' : 'TLS_RSA_WITH_AES_256_CBC_SHA', '003c' : 'TLS_RSA_WITH_AES_128_CBC_SHA256', '003d' : 'TLS_RSA_WITH_AES_256_CBC_SHA256', '009c' : 'TLS_RSA_WITH_AES_128_GCM_SHA256', '009d' : 'TLS_RSA_WITH_AES_256_GCM_SHA384', 'c02c' : 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' } dir_pcaps = "./pcaps/" pcaps = os.listdir(dir_pcaps) for pcap in pcaps: if pathlib.Path(pcap).suffix in [".pcap", ".cap", ".pcapng"]: packets = rdpcap(dir_pcaps+pcap) print(packets) for packet in packets: if packet.haslayer("Radius") and packet[IP].src == "10.10.10.40": rp = packet.getlayer("Radius") rp_hex = bytes_hex(rp).decode() for ciphersuite in ciphersuites: r = re.findall(ciphersuite, rp_hex) if r: print(ciphersuites[ciphersuite]," --> "+pcap) break else: pass get_ciphersuite()
原有代码运行输出
<128CBCSHA.pcapng: TCP:0 UDP:20 ICMP:0 Other:1> TLS_RSA_WITH_AES_128_CBC_SHA --> 128CBCSHA.pcapng TLS_RSA_WITH_AES_128_CBC_SHA256 --> 128CBCSHA.pcapng TLS_RSA_WITH_AES_128_CBC_SHA256 --> 128CBCSHA.pcapng TLS_RSA_WITH_AES_128_CBC_SHA256 --> 128CBCSHA.pcapng TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 --> 128CBCSHA.pcapng <test.pcapng: TCP:0 UDP:11 ICMP:0 Other:1> TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 --> test.pcapng TLS_RSA_WITH_AES_256_CBC_SHA256 --> test.pcapng
问题原因
原有代码的break仅作用于遍历密码套件字典的内层循环,匹配到结果后没有终止外层的数据包遍历逻辑,导致脚本会扫描完pcap内所有数据包,返回所有匹配到的结果,不符合单文件仅取首个匹配包的需求。另外rdpcap会一次性加载整个pcap文件的所有数据包到内存,处理大文件时效率极低。
修正后代码
from scapy.all import * from scapy.layers.radius import Radius import os import pathlib def get_ciphersuite(): ciphersuites = { '002f' : 'TLS_RSA_WITH_AES_128_CBC_SHA', '0035' : 'TLS_RSA_WITH_AES_256_CBC_SHA', '003c' : 'TLS_RSA_WITH_AES_128_CBC_SHA256', '003d' : 'TLS_RSA_WITH_AES_256_CBC_SHA256', '009c' : 'TLS_RSA_WITH_AES_128_GCM_SHA256', '009d' : 'TLS_RSA_WITH_AES_256_GCM_SHA384', 'c02c' : 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' } dir_pcaps = "./pcaps/" pcaps = os.listdir(dir_pcaps) for pcap in pcaps: file_path = os.path.join(dir_pcaps, pcap) if pathlib.Path(pcap).suffix not in [".pcap", ".cap", ".pcapng"]: continue print(f"处理文件: {pcap}") match_found = False # 逐包读取,无需一次性加载全文件 with PcapReader(file_path) as reader: for packet in reader: # 跳过不符合过滤规则的包 if not packet.haslayer("Radius") or packet[IP].src != "10.10.10.40": continue rp_hex = bytes_hex(packet.getlayer("Radius")).decode() # 匹配密码套件 for cs_hex, cs_name in ciphersuites.items(): if cs_hex in rp_hex: print(f"{cs_name} --> {pcap}") match_found = True break # 跳出密码套件遍历 if match_found: break # 跳出数据包遍历,直接处理下一个pcap文件 get_ciphersuite()
修改说明
- 修复循环逻辑问题:新增匹配标记,在找到首个符合要求的密码套件后,直接终止当前pcap的数据包遍历,不会继续扫描后续数据包。
- 性能优化:用
PcapReader逐包读取替代rdpcap全量加载,大文件处理速度更快,内存占用更低。 - 兼容性优化:用
os.path.join拼接文件路径,避免硬编码路径分隔符导致的跨系统运行错误。 - 移除冗余逻辑:固定十六进制子串判断不需要调用正则,直接用
in判断即可,运行效率更高。
注:当前实现通过全量Radius层hex子串匹配密码套件,存在小概率误报可能,如果需要100%精准匹配,可进一步解析Radius载荷对应字段的偏移位置做固定位置取值判断。
内容的提问来源于stack exchange,提问作者Jorge Rodriguez Mora
相关产品推荐
相关产品推荐

