【发布时间】:2014-03-16 11:17:20
【问题描述】:
我正在使用 scapy 通过 ICMP 发送数据。我需要使用 scapy 通过 ICMP 发送图像和其他文件。我能够在 ICMP 中发送简单的字符串。如何发送图像和其他文件?
【问题讨论】:
标签: python scapy icmp tunneling
我正在使用 scapy 通过 ICMP 发送数据。我需要使用 scapy 通过 ICMP 发送图像和其他文件。我能够在 ICMP 中发送简单的字符串。如何发送图像和其他文件?
【问题讨论】:
标签: python scapy icmp tunneling
我不知道scapy,所以我的答案是算法和直接python。
为了发送图像文件,您需要将图像分成块,记住您需要有一些机制来跟踪发送块的顺序。
首先,将图像文件作为二进制文件读取。然后,决定二进制数据应该划分多少。鉴于 MTU 为 1500,我建议使用 1500 - IP 标头 - ICMP 标头或 1472,以避免 IP 分段。此外,我建议使用 16 位或 32 位数字来跟踪发送块的顺序,并从 1500 中减去它。示例:1500 - IP - ICMP - 4 = 1468。
使用上面的例子,我会像这样破坏图像:
image = file("/path/to/file","rb").read()
chunk = []
interval = 1500 - 20 - 8 - 4
for n in range(0, len(image), interval):
chunk.append(image[n:n + interval])
图像现在是分块的,我会将跟踪字节添加到每个块中。它可以是前缀或后缀,你的选择。我选择了前缀:
for n in range(len(chunk)):
chunk[n] = struct.pack(">I", n) + chunk[n]
现在我们已经标记了要跟踪的块,我们需要构建 ICMP 标头,并附加每个块。但是我们使用哪种类型/代码?在这个用例中,我们将构建一个 ECHO REQUEST 数据包(其他类型,例如 0 或 3 是未经请求的,可能会导致接收内核不将数据包转发到您的 ICMP 套接字处理程序)。另外,需要注意的重要一点:您需要校验和代码来计算 ICMP 校验和:
icmp_chunks = []
for img_piece in chunk:
icmp = struct.pack(">BBHHH%ds" % len(img_piece), 8, 0, 0, 0, 0, img_piece)
icmp = struct.pack(">BBHHH%ds" % len(img_piece), 8, 0, cksum(icmp), 0, 0, img_piece)
icmp_chunks.append(icmp)
重申一下,请注意第二个 icmp 标头数据包中的 cksum(icmp) 参数。这个校验和是必需的,否则如果不正确,接收内核可能不会将数据包转发到任何 ICMP 套接字处理程序。还要注意第 4 和第 5 个参数为零:这些是“标识符”和“序列号”字段。通常,这些用于存储进程 ID 和增量编号(分别)。套接字对象这样做是为了跟踪哪个套接字发送了什么以及发送了多少。在这个用例中,由于我们正在发送一个未经请求的 ECHO REPLY,因此您可以对接收端进行编码以查找类型 0,并进一步在发送的块中查找您的跟踪字节。因此,现在我将标识符和序列字段保留为零。如果您想知道为什么我构造了两个 icmp 标头,那是因为内核基于初始校验和字段为零来正确计算校验和。
此时,我们现在有了 icmp 标头并准备发送:
for i in icmp_chunks:
[socket].sendto(i, ("hostname-or-ip", 0))
我假设 [socket] 对象是 scapy 或您自己的套接字对象。
在接收端,您读回数据并查找您的图像负载,将每个负载重建回其原始顺序。但是,您仍然需要一些方法来确定是否所有接收到的块确实都是它们。也许在发送图像块之前考虑如何构造一个指示总预期大小的初始字节序列。
希望这会有所帮助。
更新:我测试了向 Ubuntu Linux 发送未经请求的 0 型数据包,并注意到接收内核没有没有将数据包传递给我的处理程序。所以我修改了我的解释来解释这一点。
【讨论】:
我想您已经发现了 Internet 的发明者开发 TCP 的原因。 ICMP 数据包中的有效负载大小有限制。大多数网络对以太网数据包的大小有 1500 字节的总限制,因此对于 20 字节的 IP 标头和 8 字节的 ICMP 标头,单个数据包中的最大有效负载大小将是 1472 个八位字节。这对于许多图像文件来说是不够的。
您需要一种方法,将您的图像数据流分解成大约该大小的块,以多个 ICMP 数据包的形式发送它们,然后在接收器上将它们重新组合成一个数据流。
考虑到不能保证 ICMP 数据包按顺序接收,并且确实不能保证它们都将按顺序接收,您需要将某种序列号放入各个数据包中,以便重新组装它们为了。您可能还需要一些超时逻辑,以便您的接收机器可以确定数据包丢失,因此图像永远不会完成。
RTP 和 TCP 是两个基于 IP 的协议。它们被详细记录在案,您可以从这些文档中了解如何做您想做的事情以及一些陷阱和性能影响。
【讨论】: