Python3 Scapy - 嗅探 IP 数据包碎片
Python3 Scapy - Sniff fragmented IP packets
我尝试使用以下设置来简化我的问题。
- 我本地接口 (192.168.183.130) 上端口 1337 上的一个简单的 netcat UDP 侦听器
- 一个简单的 netcat UDP 客户端连接到端口 1337 上的侦听器(来自 192.168.183.128)
- 192.168.183.130
上的一个非常基本的 scapy 嗅探器 运行
Scapy 嗅探器运行 root 权限:
from scapy.all import sniff, IP, UDP
def print_package(packet):
packet.show()
sniff(filter="ip dst host 192.168.183.130 and dst port 1337", iface="ens33", prn=print_package)
发送具有 1500 字节 MTU 限制的 IP 数据包/UDP 帧非常有效,并且数据包按预期打印到标准输出。一旦我成功限制并且 IP 协议创建片段,嗅探器只会捕获第一个数据包(正确的标志、len 等)
在下面的示例中,我在使用 netcat 发送 3200 * "A" 之前从 nc 客户端向侦听器发送了一个简单的字符串 'next message will be 3200 * "A"'。在 netcat 使用的 UDP 套接字接收它之前,数据包被分成三个 IP 数据包并由堆栈正确重组,因此一切都按照我期望的网络方式工作。 Scapy 只嗅探三个数据包中的第一个,我不明白为什么会这样。
截图显示了expected/correct在wireshark中处理短信和三个IP片段:
以下代码片段显示了 scapy 到标准输出的输出:
sudo python3 scapy_test.py
###[ Ethernet ]###
dst = 00:0c:29:fa:93:72
src = 00:0c:29:15:2a:11
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 59
id = 18075
flags = DF
frag = 0
ttl = 64
proto = udp
chksum = 0x3c3
src = 192.168.183.128
dst = 192.168.183.130
\options \
###[ UDP ]###
sport = 59833
dport = 1337
len = 39
chksum = 0xdaa0
###[ Raw ]###
load = 'next message will be 3200 * "A"\n'
###[ Ethernet ]###
dst = 00:0c:29:fa:93:72
src = 00:0c:29:15:2a:11
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 1500
id = 20389
flags = MF
frag = 0
ttl = 64
proto = udp
chksum = 0x1518
src = 192.168.183.128
dst = 192.168.183.130
\options \
###[ UDP ]###
sport = 59833
dport = 1337
len = 3209
chksum = 0x25bd
###[ Raw ]###
load = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
为什么其他 IP 片段丢失了,我该如何嗅探它们?
我知道 sniff 中的会话参数,但我真的没有运气用 session=IPSession
重新组装数据包。 (无论如何,这不是我想要实现的,对于我的应用程序,我想嗅探所有片段,更改它们的一部分并将它们转发给另一个 address/socket。)
我终于自己弄明白了,所以我要留下答案:
问题出在嗅探器的过滤器上:
sniff(filter="ip dst host 192.168.183.130 and dst port 1337", iface="ens33", prn=print_package)
第一个之后的 IP 片段没有 UDP 部分,因此没有目标端口,因此 scapy 过滤器不会捕获它们。为了解决这个问题,我扩展了过滤器以捕获 dst 端口 1337 或具有偏移量的片段。我偶然发现了这个备忘单 https://github.com/SergK/cheatsheat-tcpdump/blob/master/tcpdump_advanced_filters.txt,它为这个问题提供了有效的 berkeley 语法,并最终得到了这个过滤器(用于简化的问题)。
sniff(filter="ip dst host 192.168.183.130 and ((src port 1337) or (((ip[6:2] > 0) or (ip[7] > 0)) and (not ip[6] = 64))", iface="ens33", prn=print_package)
这会检查数据包的分段偏移量是否 >0(第六字节(标志)或第七字节的前三位之后的任何内容 >0)以及“不分段”位是否为没有设置。如果这是真的,它是一个 IP 片段,嗅探器应该嗅探它。
我尝试使用以下设置来简化我的问题。
- 我本地接口 (192.168.183.130) 上端口 1337 上的一个简单的 netcat UDP 侦听器
- 一个简单的 netcat UDP 客户端连接到端口 1337 上的侦听器(来自 192.168.183.128)
- 192.168.183.130 上的一个非常基本的 scapy 嗅探器 运行
Scapy 嗅探器运行 root 权限:
from scapy.all import sniff, IP, UDP
def print_package(packet):
packet.show()
sniff(filter="ip dst host 192.168.183.130 and dst port 1337", iface="ens33", prn=print_package)
发送具有 1500 字节 MTU 限制的 IP 数据包/UDP 帧非常有效,并且数据包按预期打印到标准输出。一旦我成功限制并且 IP 协议创建片段,嗅探器只会捕获第一个数据包(正确的标志、len 等)
在下面的示例中,我在使用 netcat 发送 3200 * "A" 之前从 nc 客户端向侦听器发送了一个简单的字符串 'next message will be 3200 * "A"'。在 netcat 使用的 UDP 套接字接收它之前,数据包被分成三个 IP 数据包并由堆栈正确重组,因此一切都按照我期望的网络方式工作。 Scapy 只嗅探三个数据包中的第一个,我不明白为什么会这样。
截图显示了expected/correct在wireshark中处理短信和三个IP片段:
以下代码片段显示了 scapy 到标准输出的输出:
sudo python3 scapy_test.py
###[ Ethernet ]###
dst = 00:0c:29:fa:93:72
src = 00:0c:29:15:2a:11
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 59
id = 18075
flags = DF
frag = 0
ttl = 64
proto = udp
chksum = 0x3c3
src = 192.168.183.128
dst = 192.168.183.130
\options \
###[ UDP ]###
sport = 59833
dport = 1337
len = 39
chksum = 0xdaa0
###[ Raw ]###
load = 'next message will be 3200 * "A"\n'
###[ Ethernet ]###
dst = 00:0c:29:fa:93:72
src = 00:0c:29:15:2a:11
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 1500
id = 20389
flags = MF
frag = 0
ttl = 64
proto = udp
chksum = 0x1518
src = 192.168.183.128
dst = 192.168.183.130
\options \
###[ UDP ]###
sport = 59833
dport = 1337
len = 3209
chksum = 0x25bd
###[ Raw ]###
load = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
为什么其他 IP 片段丢失了,我该如何嗅探它们?
我知道 sniff 中的会话参数,但我真的没有运气用 session=IPSession
重新组装数据包。 (无论如何,这不是我想要实现的,对于我的应用程序,我想嗅探所有片段,更改它们的一部分并将它们转发给另一个 address/socket。)
我终于自己弄明白了,所以我要留下答案:
问题出在嗅探器的过滤器上:
sniff(filter="ip dst host 192.168.183.130 and dst port 1337", iface="ens33", prn=print_package)
第一个之后的 IP 片段没有 UDP 部分,因此没有目标端口,因此 scapy 过滤器不会捕获它们。为了解决这个问题,我扩展了过滤器以捕获 dst 端口 1337 或具有偏移量的片段。我偶然发现了这个备忘单 https://github.com/SergK/cheatsheat-tcpdump/blob/master/tcpdump_advanced_filters.txt,它为这个问题提供了有效的 berkeley 语法,并最终得到了这个过滤器(用于简化的问题)。
sniff(filter="ip dst host 192.168.183.130 and ((src port 1337) or (((ip[6:2] > 0) or (ip[7] > 0)) and (not ip[6] = 64))", iface="ens33", prn=print_package)
这会检查数据包的分段偏移量是否 >0(第六字节(标志)或第七字节的前三位之后的任何内容 >0)以及“不分段”位是否为没有设置。如果这是真的,它是一个 IP 片段,嗅探器应该嗅探它。