使用Scapy提取TCP负载遇NoneType异常及AttributeError问题排查
Scapy提取TCP负载时触发NoneType异常的问题分析
问题场景
我最近尝试用Scapy提取TCP报文的单个字符负载,但处理前两个报文后就持续触发NoneType异常。我的代码是这样的:
from scapy.all import * import base64 capture = rdpcap('Data.pcapng') # pcap file output = open('output.bin','wb') # save dumped data to output.bin for packet in capture: # if packet is ICMP and type is 8 (echo request) if packet[TCP].src == '172.16.139.128': output.write(packet[TCP].payload) # write packet data to output.bin
触发的异常信息:
Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scapy/packet.py", line 372, in __getattr__ fld, v = self.getfield_and_val(attr) TypeError: cannot unpack non-iterable NoneType object During handling of the above exception, another exception occurred: Traceback (most recent call last): File "exploit.py", line 10, in <module> if packet[TCP].src == '172.16.139.128': File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scapy/packet.py", line 374, in __getattr__ return self.payload.__getattr__(attr) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scapy/packet.py", line 372, in __getattr__ fld, v = self.getfield_and_val(attr) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scapy/packet.py", line 1600, in getfield_and_val raise AttributeError(attr) AttributeError: src
想搞清楚这个异常的成因,而且预期应该能输出更多内容。
异常成因分析
你这代码其实踩了两个关键的坑:
- 没做协议存在性检查:pcap文件里肯定不是所有报文都是TCP包,可能混着ARP、ICMP或者其他协议的包。你直接用
packet[TCP]访问TCP层,遇到非TCP包时这个调用会返回None,后续再访问.src自然就会触发NoneType相关的异常。 - 属性搞混了协议层:TCP层根本没有
src这个属性啊!src是IP层的属性,用来表示源IP地址;TCP层对应的是源端口sport和目的端口dport。你把IP层的属性放到TCP层上调用,不出错才怪。
修复后的代码
针对这两个问题,我调整了代码,不仅解决了异常,还满足你提取单个字符负载的需求:
from scapy.all import * capture = rdpcap('Data.pcapng') output = open('output.bin', 'wb') for packet in capture: # 先确认报文同时包含IP和TCP层,避免访问不存在的协议 if IP in packet and TCP in packet: # 从IP层获取源IP地址,这才是正确的姿势 if packet[IP].src == '172.16.139.128': # 先检查TCP有没有负载,避免写入空数据 if packet[TCP].payload: # 提取负载的第一个字节(单个字符)写入文件 output.write(bytes(packet[TCP].payload)[:1]) # 记得关闭文件,避免数据丢失 output.close()
关键修改点说明
- 协议存在性校验:用
IP in packet和TCP in packet过滤掉不符合要求的报文,确保只处理有IP和TCP层的包。 - 修正源IP的获取层:把
packet[TCP].src改成packet[IP].src,这才是获取源IP的正确方式。 - 负载非空检查:增加
if packet[TCP].payload判断,避免TCP没有负载时写入空内容。 - 提取单个字符:通过
bytes(packet[TCP].payload)[:1]截取负载的第一个字节,满足你提取单个字符的需求。
内容的提问来源于stack exchange,提问作者flowermia
相关产品推荐
相关产品推荐

