重新注入捕获的数据包会导致错误的以太网校验和

时间:2018-06-26 14:21:52

标签: python network-programming scapy

在玩鹰鱼时,我观察到以下行为。虚假的手册页建议像这样的示例

a=sniff(filter="tcp port 110")
...
sendp(a)

重新注入捕获的数据包。但是,当我自己尝试此操作时,wireshark告诉我所有重新注入的数据包的 ETHERNET FRAME CHECK SEQUENCE INCORRECT 。 (捕获和重新注入的数据包无关紧要。)当我用scapy交互地检查数据包时,我注意到未显示以太网预告片(和校验和)。而且,没有方法可以修改或设置预告片。

显然,scapy无法正常工作-我想念什么?如何重新插入以太网框架的副本,使其看起来有效?

详细示例

在此示例中,我考虑了ARP数据包。但是,其他数据包类型也存在此问题。

这是wireshark记录的内容(由tcpdump -v -XX -r ...转储):

14:05:39.517932 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.141.150 tell 192.168.140.193, length 46
    0x0000:  ffff ffff ffff 90b1 1c47 c81e 0806 0001  .........G......
    0x0010:  0800 0604 0001 90b1 1c47 c81e c0a8 8cc1  .........G......
    0x0020:  0000 0000 0000 c0a8 8d96 0000 0000 0000  ................
    0x0030:  0000 0000 0000 0000 0000 0000            ............

这是scapy3的看法:

>>> x = sniff(count=1, filter='arp')
>>> bytes(x[0])
b'\xff\xff\xff\xff\xff\xff\x90\xb1\x1cG\xc8\x1e\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x90\xb1\x1cG\xc8\x1e\xc0\xa8\x8c\xc1\x00\x00\x00\x00\x00\x00\xc0\xa8\x8d\x96\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> x[0].show()
###[ Ethernet ]### 
  dst= ff:ff:ff:ff:ff:ff
  src= 90:b1:1c:47:c8:1e
  type= ARP
###[ ARP ]### 
     hwtype= 0x1
     ptype= 0x800
     hwlen= 6
     plen= 4
     op= who-has
     hwsrc= 90:b1:1c:47:c8:1e
     psrc= 192.168.140.193
     hwdst= 00:00:00:00:00:00
     pdst= 192.168.141.150
###[ Padding ]### 
        load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

然后...

>>> sendp(x[0])
.
Sent 1 packets.

这是wireshark捕获的

14:14:44.901556 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.141.150 tell 192.168.140.193, length 60
    0x0000:  ffff ffff ffff 90b1 1c47 c81e 0806 0001  .........G......
    0x0010:  0800 0604 0001 90b1 1c47 c81e c0a8 8cc1  .........G......
    0x0020:  0000 0000 0000 c0a8 8d96 0000 0000 0000  ................
    0x0030:  0000 0000 0000 0000 0000 0000 3203 3136  ............2.16
    0x0040:  3803 3139 3207 696e 2d61                 8.192.in-a

如您所见,最后14个字节非常奇怪。实际上,常规ARP数据包的长度为46,而不是60。(Wireshark将其显示为长度为74,请参见下图)。

Wireshark's view

strace

这是strace在捕获时看到的内容(请注意:这是与上例不同的数据包)

2552  recvfrom(12, "\xff\xff\xff\xff\xff\xff\x00\x50\x56\xbf\x0c\x83\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x50\x56\xbf\x0c\x83\xc0\xa8\x8d\xb0\x00\x00\x00\x00\x00\x00\xc0\xa8\x8e\x6b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 65535, 0, {sa_family=AF_PACKET, sa_data="\x08\x06\x02\x00\x00\x00\x01\x00\x01\x06\x00\x50\x56\xbf\x0c\x83"}, [20->18]) = 60

这就是strace在重新发送(与之前的捕获匹配)时看到的内容

2552  sendto(12, "\xff\xff\xff\xff\xff\xff\x00\x50\x56\xbf\x0c\x83\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x50\x56\xbf\x0c\x83\xc0\xa8\x8d\xb0\x00\x00\x00\x00\x00\x00\xc0\xa8\x8e\x6b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 60, 0, NULL, 0) = 60

系统信息

以防万一,请注意:该平台是Kali Linux(4.16.0-kali2-amd64),该平台定期保持最新状态,不予干预。操作系统在Virtualbox VM(Virtualbox 5.2.12)中运行。我尝试过的另一个平台是带有Kali Linux(无VM)的DELL PC。

到目前为止的见识

一个以太网帧必须至少包含64个字节,包括14个字节的标头和4个字节的FCS,因此有效负载必须至少具有46个字节(Wireshark通常显示标头,但不显示FCS,这就是Wireshark显示的原因ARP数据包有60个字节而不是64个字节)。 ARP数据包(用于以太网/ IPv4)具有28个字节。剩下18个字节的填充。由于某些原因,我仍然不知道,如果我通过sendto()发送60字节(不包括FCS)的原始数据,那么(驱动程序?)会附加另外14字节,弄乱了FCS。

下面是我在scapy中调用strace -x -s 1000 -e trace=%network -p ...时得到的sendp(pkt)的转储(对于另一个数据包):

socket(AF_PACKET, SOCK_RAW, 768)        = 12
setsockopt(12, SOL_SOCKET, SO_RCVBUF, [0], 4) = 0
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 13
setsockopt(12, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0
bind(12, {sa_family=AF_PACKET, sll_protocol=htons(ETH_P_ALL), sll_ifindex=if_nametoindex("eth0"), sll_hatype=ARPHRD_NETROM, sll_pkttype=PACKET_HOST, sll_halen=0}, 20) = 0
setsockopt(12, SOL_SOCKET, SO_RCVBUF, [1073741824], 4) = 0
setsockopt(12, SOL_SOCKET, SO_SNDBUF, [1073741824], 4) = 0
getsockname(12, {sa_family=AF_PACKET, sa_data="\x00\x03\x02\x00\x00\x00\x01\x00\x00\x06\x08\x00\x27\xbc\xeb\x8a"}, [20->18]) = 0
sendto(12, "\xff\xff\xff\xff\xff\xff\x00\x50\x56\xbf\x0c\x83\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x50\x56\xbf\x0c\x83\xc0\xa8\x8d\xb0\x00\x00\x00\x00\x00\x00\xc0\xa8\x8e\x6b\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 60, 0, NULL, 0) = 60
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 11
setsockopt(12, SOL_PACKET, PACKET_DROP_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0

1 个答案:

答案 0 :(得分:0)

您可能正在使用Wirehark在生成它们的盒子上捕获传出数据包,这些传出数据包就是您看到的带有不正确帧检查序列(FCS)的数据包。这是因为,在发送时,网络适配器实际上在发送帧时进行计算并附加FCS,但是提供给Wireshark的帧的副本是从内存版本转移到网络之前的适配器。 (几乎所有现代的NIC都是如此:校验和是在适配器中计算的,因为它可以使用硬件CRC生成器,其速度比软件快。)

因此,即使您可能未经修改地重新传输先前接收到的帧,其原始FCS也会在此过程中被丢弃,并且在输出时会生成新的FCS,但是在传输盒上,您可以没看到,所以wireshark正在查看从libpcap获得的缓冲区中帧内该位置的任何数据(可能是全零)。

我敢打赌,如果您在LAN上的另一个站点(例如,目的地)捕获了这些相同的数据包,您会发现它们实际上具有正确的校验和。

顺便说一下,wireshark的“以太网协议首选项”窗格中有几个设置可以控制如何处理/报告这些设置。