如何使用python分析Wireshark捕获的网络数据包?

背景

在进行网络带宽相关的数据分析时,经常会用到Wireshark这类工具,它提供一个图形界面,帮助我们捕获特定端口的数据包、查看数据包各层协议的具体情况等。但有时候,我们常常需要将分析过程融入到代码中,实现大量网络数据包上的自动化字段抽取、数据统计等。

本文将会介绍:

  1. 如何基于 tshark 在 python 程序中实现自动化的网络数据包分析
  2. tshark 部分参数的使用经验,如何设置参数使其更适合 python 分析场景

使用经验

pyshark vs tshark

我之前没有任何网络分析相关的经验,仅有一定的python基础,所以自然地通过网络搜索首先接触到 pyshark 这个库,但是尝试使用以后,发现了以下几个点,致使我放弃 pyshark 转而使用比较笨的方式直接使用 tshark:

  1. pyshark 本质上是对 tshark 的封装,tshark 是安装 wireshark 时就会自动安装的对应命令行工具。

    可以理解为,wireshark 图形化界面上显示的其实也是 tshark 运行的结果,wireshark 将 tshark 的结果按自己的思路组装到图形化界面上;而 pyshark 按照 pyshark 作者的思路,将 tshark 的结果组织到自己定义的类中,配合一些类的方法实现各层协议字段的访问、数据包具体情况的展示等

  2. 在使用自定义的 lua 脚本解析网络数据包时,wireshark / tshark 的结果和 pyshark 的结果不一致,pyshark 会导致层级消失、嵌套协议解析失败等问题,这可能和 pyshark 很久没维护或没有对使用自定义 lua 脚本的场景做很好的兼容有关。

pcap -> json

我的场景是一个后分析场景,即网络数据包先行在一个远程服务器上通过 tcpdump/wireshark 等工具启动、结束捕获,得到一个pcap/.pcapng 等网络数据包文件,基于该文件进行 python 自动化分析或数据抽取。研究 tshark 部分参数以后,我发现最简单的思路是,使用 tshark 的输出功能先行将.pcap 文件转换为 json 文件,就能很自然地进入python程序的舒适区了。

可以在 python 程序中使用 subprocess.run() 或手动在命令行运行:

tshark -r path/to/cap.pcap -T ek -w path/to/destfile.json
# or
with open(path/to/json, 'w', encoding='utf-8') as f:
	subprocess.run(['tshark', '-r', 'path/to/cap.pcap', '-T', 'ek', '-w', 'path/to/destfile.json'], stdout=f)
  • 注意:.pcap 文件中的每个数据包都会被转换为一个字典结构,包含各层的字段和对应的值,因此,如果使用 -T json,会生成一个巨大的 list,包含所有的数据包解析字典,这导致之后我们在 load 的时候,内存压力非常大,必须 json.load(整个list)。更好的做法是使用 -T ek。ek 是 tshark 为 elastic search 检索准备的,它生成的内容更接近 jsonl:每个数据包会对应两个json字符串 (一个包含 index 键,用于作为 elastic search 的 index,一个包含所有的解析字段,用于作为 elastic search 的 key)。这样的结果在 load 时内存压力会小很多,因为我们可以逐行读取结果文件,使用 json.loads(),放弃包含 index 的行,留下解析结果。

使用自定义 lua 脚本将数据包按照自定义协议解析

tshark 的解析默认基于自带的协议进行解析,有时候数据包的编码刚好能够解析出来,有时候就会失败,尤其是如果我们的网络协议是自己设计的,就需要自己的配套解析方法。

  1. 将自定义网络协议的解析方法(通常是一个 lua 脚本) 加载到 tshark 中。

    通常在/Users/username/.config/wireshark 中查找/创建一个 init.lua 文件,然后在其中添加 dofile("path/to/lua_script") ,即可使得wireshark/tshark在运行时都先将 lua 脚本加载进它配置的协议中

  2. 脚本被加载成功以后,wireshark 的 decode_as 功能就能看见 lua 脚本中定义的协议的名称。这种自定义的协议的数据包通常只在特定端口发送和接收。类似 wireshark 上右键数据包选择的 decode_as 功能需要设置数据包过滤规则和对应的解析协议,tshark中也有参数实现对应功能,和 wireshark 图形化界面上几乎一样:

    -d udp.port==xxxx,my_protocol

减轻磁盘存储压力

如果尝试上述命令,你或许会发现,一个100MB的.pcap文件,可能通过 -T ek 会变成数个G的大小,如果捕获的时间很长,这个数字会更大。尽管加载到内存中是逐行读取,内存没有压力,但是这给磁盘存储带来了压力,如果你想要分析的是特定的协议层,其他层的解析信息既浪费存储又浪费读取解析的时间。

tshark 提供 -j 和 -J 两个参数,分别对字典中的嵌套结构实现细粒度和粗粒度的过滤(过滤的结果是,key保留,但value被覆盖为"filtered"):

# 只保留 UDP 层的所有字段,那么 ip 层对应的 value 就会变成 "filtered"
-J "UDP"

# 只保留 ip 层的特定字段,那么 ip 层所有字段会被保留,但没被 -j 指定的字段对应的 value 都会变成 filtered
-j "ip ip.addr frame frame.len"

两者可以结合使用,-j 指定的字段对应的父节点会被保留,不会被 -J 过滤掉,这样可以大大减少无用信息的占用

  • 注:-J/-j 对应的参数值应该参考 wireshark 显示的填,而不是参考 -T ek 的结果文件中显示的字段名。比如 ip.addr 在wireshark的图形化界面上显示的就是一个折叠的ip层级,里面有addr字段,但是在tshark -T ek 中显示的字段名可能是 ip_ip_addr,我们应该填 ip.addr 而不是 ip.ip_ip_addr

更有效的压缩方法是结合 display_filter,和Wireshark的图形化界面一样,可以筛选要显示出来的数据包,比如通过“custom_field == value” 的形式筛选特定字段等于特定值的数据包。对应到 tshark 就可以使用

tshark -Y "field1 == value1 or field2 == value2" -w outfile

这样只有被筛选出来的数据包才会被写入到文件中,结合 -j / -J 使用可以大大压缩磁盘占用

如果以上仍然无法显著减小输出文件的大小,可以尝试 subprocess PIPE,让主程序和 tshark command 进程通信,处理完以后再写入文件,能避免很多无用信息写入文件中:

process = subprocess.Popen(tshark_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
with open(outfile_json, 'w', encoding='utf-8') as f:
	for line in process.stdout:
		# 过滤掉加载自定义lua脚本会出现的提示
		if 'init.lua' in line:
			continue
		data = json.loads(line)
		if 'index' in data:
			...
		else:
			# 字段抽取和处理,抽取需要的信息
			...process the decoded_dict...
			f.write(json.dumps(data, ensure_ascii=False) + '\n')

return_code = process.wait()
assert return_code == 0, 'tshark command completion failed!'
		

字段对应的原始编码

在部分情况下我们需要分析每个字段的字节长度,这个时候增加 -x 参数即可,会添加每个字段对应的 hex 值,但同时要注意,这也会增加磁盘存储的负担

python字段抽取

接下来就可以按照简单的python程序分析json文件那样完成字段访问、数据分析等工作了,这部分不再赘述。

强烈建议通过肉眼观察关心的数据包的键值情况,然后通过直接访问的方式读取字段,避免在解析结果字典上for循环,这可能会比你想象中耗时间(因为字段全都是保留的,只是值被 filtered 覆盖了)

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MetLightt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值