При игре со scapy я наблюдал следующее поведение. Страница руководства scapy предлагает в качестве примера что-то вроде
a=sniff(filter="tcp port 110")
...
sendp(a)
для повторного ввода захваченных пакетов. Однако, когда я попробовал это сам, wireshark сообщает мне ПОСЛЕДОВАТЕЛЬНОСТЬ ПРОВЕРКИ КАДРА В ETHERNET на всех повторно введенных пакетах. (Неважно, какие пакеты я собираю и повторно внедряю.) Когда я исследовал пакеты в интерактивном режиме со scapy, я заметил, что трейлер Ethernet (и контрольная сумма) не отображаются. Более того, нет способа изменить или установить трейлер.
Видимо, scapy не работает так, как я ожидаю - что мне не хватает? Как я могу повторно внедрить копию кадра Ethernet, чтобы он выглядел как действительный?
Подробный пример
Для этого примера я рассматриваю пакет 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, см. Изображение ниже).
Трассирование
Это то, что 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 (Virtualbox 5.2.12). Другая платформа, на которой я пробовал это, - это компьютер DELL с Kali Linux (без виртуальной машины).
Понимание до сих пор
Фрейм Ethernet должен содержать не менее 64 байтов, включая заголовок 14 байтов и 4 байта FCS, поэтому полезная нагрузка должна содержать не менее 46 байтов (Wireshark обычно показывает заголовок, но не FCS, поэтому Wireshark показывает пакет ARP должен иметь 60 байтов вместо 64). Пакет ARP (для Ethernet / IPv4) имеет 28 байтов. Это оставляет 18 байтов заполнения. По какой-то причине мне пока неизвестно, если я отправлю 60 байтов (не считая FCS) в исходном виде через sendto()
, что-то (драйвер?) Добавит еще 14 байтов, что испортит FCS.
Ниже приведен дамп (для еще одного пакета) strace -x -s 1000 -e trace=%network -p ...
, который я получаю при вызове sendp(pkt)
в scapy:
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