scapy icon indicating copy to clipboard operation
scapy copied to clipboard

ARP bug where source MAC is 00:00:00:00:00:00

Open FutureSharks opened this issue 5 years ago • 14 comments

Brief description

When running ARP scan of a subnet directed at a specific MAC, one of the packets uses the source HW address of 00:00:00:00:00:00.

Scapy code:

from scapy.all import srp, Ether, ARP
from scapy.all import conf as scapy_conf
scapy_conf.promisc=0
scapy_conf.sniff_promisc=0

answered,unanswered = srp(Ether(dst='aa:bb:cc:dd:ee:ff')/ARP(pdst='192.168.178.0/24'), timeout=1, verbose=False)

Packet dump looks like this:

18:12:52.810860 00:0e:8e:58:d6:af > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.178.31 tell 192.168.178.34, length 28
18:12:52.813976 00:0e:8e:58:d6:af > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.178.32 tell 192.168.178.34, length 28
18:12:52.819256 00:0e:8e:58:d6:af > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.178.33 tell 192.168.178.34, length 28
18:12:52.826365 00:00:00:00:00:00 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.178.34 tell 192.168.178.34, length 28
18:12:52.829909 00:0e:8e:58:d6:af > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.178.35 tell 192.168.178.34, length 28

Environment

  • Scapy version: master
  • Python version: 3
  • Operating System: Debian buster

FutureSharks avatar Dec 30 '19 17:12 FutureSharks

Resolves https://github.com/FutureSharks/rpi-security/issues/53

FutureSharks avatar Dec 30 '19 17:12 FutureSharks

Hi, could you provide the output of the following commands:

>>> conf.route
>>> conf.iface

p-l- avatar Dec 30 '19 20:12 p-l-

Sure:

>>> from scapy.all import conf
>>> conf.route
Network        Netmask        Gateway        Iface  Output IP       Metric
0.0.0.0        0.0.0.0        192.168.178.1  wlan1  192.168.178.35  303
127.0.0.0      255.0.0.0      0.0.0.0        lo     127.0.0.1       1
192.168.178.0  255.255.255.0  0.0.0.0        wlan1  192.168.178.35  303
>>> conf.iface
'wlan1'

FutureSharks avatar Dec 30 '19 20:12 FutureSharks

That' really weird: I cannot reproduce that bug. Do we agree you are talking about the field hwsrc in the ARP layer of the sent packets?

p-l- avatar Dec 31 '19 07:12 p-l-

Do we agree you are talking about the field hwsrc in the ARP layer of the sent packets?

I think so. Will the capture files help?

kamene-scapy-pcap-files.zip

And this is the adapter arrangement:

# iw dev
phy#1
	Interface mon0
		ifindex 4
		wdev 0x100000002
		addr 00:0e:8e:58:d6:af
		type monitor
		txpower 26.00 dBm
	Interface wlan1
		ifindex 3
		wdev 0x100000001
		addr 00:0e:8e:58:d6:af
		ssid XXXX
		type managed
		channel 100 (5500 MHz), width: 40 MHz, center1: 5510 MHz
		txpower 26.00 dBm
phy#0
	Interface wlan0
		ifindex 2
		wdev 0x1
		addr b8:27:eb:cb:b6:5d
		type managed
		channel 34 (5170 MHz), width: 20 MHz, center1: 5170 MHz
		txpower 31.00 dBm

Something else I can do to help debug it?

FutureSharks avatar Dec 31 '19 14:12 FutureSharks

OK thanks for the capture. It seems that the bug only occurs when .pdst is your own IP address. Am I right?

p-l- avatar Jan 02 '20 18:01 p-l-

Correct.

Here, you can reproduce it easily using docker....

$ docker run --name python -it python:latest bash

root@28a734defeca:/# apt update; apt install -y tcpdump

root@28a734defeca:/# pip3 install scapy

root@28a734defeca:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
    link/tunnel6 :: brd ::
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever



root@28a734defeca:/# python3
Python 3.8.1 (default, Dec 28 2019, 05:31:15)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from scapy.all import srp, Ether, ARP
>>> from scapy.all import conf as scapy_conf
>>> scapy_conf.promisc=0
>>> scapy_conf.sniff_promisc=0
>>>
>>> answered,unanswered = srp(Ether(dst='aa:bb:cc:dd:ee:ff')/ARP(pdst='172.17.0.0/24'), timeout=1, verbose=False)

Now run tcpdump in this container in another terminal before the srp(Ether.. line:

$ docker exec -it python tcpdump -c 10 -nn -e -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
21:08:10.197833 02:42:ac:11:00:02 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 172.17.0.0 tell 172.17.0.2, length 28
21:08:10.198868 02:42:ac:11:00:02 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 172.17.0.1 tell 172.17.0.2, length 28
21:08:10.199823 00:00:00:00:00:00 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 172.17.0.2 tell 172.17.0.2, length 28
21:08:10.200403 02:42:ac:11:00:02 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 172.17.0.3 tell 172.17.0.2, length 28
21:08:10.200908 02:42:ac:11:00:02 > aa:bb:cc:dd:ee:ff, ethertype ARP (0x0806), length 42: Request who-has 172.17.0.4 tell 172.17.0.2, length 28
...

FutureSharks avatar Jan 02 '20 21:01 FutureSharks

You don't even need to actually send the packets:

>>> ARP(pdst="192.168.0.10").hwsrc  # my IP address
'00:00:00:00:00:00'
>>> ARP(pdst="192.168.0.11").hwsrc  # another IP address
'xx:xx:xx:xx:xx:xx'  # my MAC address

p-l- avatar Jan 03 '20 05:01 p-l-

Actually, the bug is not related to the ARP layer, but to the SourceMACField field. It also exists in Ether(), for example.

The thing is: I am not 100% convinced that this is, per se, a bug. It is normal that one do not send on an Ethernet wire a packet with src == dst.

The issue can be tracked down to the .route() methods (of both Packet and Route objects):

>>> ARP(pdst="192.168.0.10").route()  # my IP address
('lo', '192.168.0.10', '0.0.0.0')  # 'lo' is the loopback interface
>>> ARP(pdst="192.168.0.11").route()  # another IP address
('eth0', '192.168.0.10', '0.0.0.0')
>>> conf.route.route("192.168.0.10")
('lo', '192.168.0.10', '0.0.0.0')
>>> conf.route.route("192.168.0.11")
('eth0', '192.168.0.10', '0.0.0.0')

This seems OK to me: when you send a packet to your own address, you use the loopback interface.

What do you think @guedou @gpotter2 @FutureSharks?

p-l- avatar Jan 12 '20 11:01 p-l-

when you send a packet to your own address, you use the loopback interface

I guess that's correct in the real world. If I ping my own eth0 address, it looks like this:

14:23:26.257679 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 98: 172.17.0.2 > 172.17.0.2: ICMP echo request, id 326, seq 1, length 64
14:23:26.257701 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 98: 172.17.0.2 > 172.17.0.2: ICMP echo reply, id 326, seq 1, length 64

But then should scapy set the destination MAC to also be 00:00:00:00:00:00? This would be correct. But then this isn't quite following dst='aa:bb:cc:dd:ee:ff' argument.

FutureSharks avatar Jan 13 '20 14:01 FutureSharks

@p-l- the current behavior seems strange at first. After reading your comments, and giving it a thought, I don't think that it is a bug.

guedou avatar Jan 13 '20 21:01 guedou

I still think it's a bug.

If you're going to use 00:00:00:00:00:00 as a source address, then you should also send that packet to 00:00:00:00:00:00, just like any other packets sent to lo interface. But if you're going to send it out a real interface, like in this issue, then using 00:00:00:00:00:00 makes no sense.

FutureSharks avatar Jan 14 '20 11:01 FutureSharks

Good point @FutureSharks. We may (no idea how) check for SourceMACField values when the packet is about to leave the network interface. Regarding your analogy with the dst addr, I think you are wrong however, since you have explicitly set a value for it.

p-l- avatar Jan 17 '20 06:01 p-l-

Not sure if this helps draw more attention to the issue... But when using the arping() function, there seems to be no way to set a "hwsrc"?. This leaves you stuck to deal with the above all zeroes issue and effectively poisoning the arp tables of neighboring hosts if you want to use arping().

nickmuse avatar Aug 16 '21 17:08 nickmuse

If possible, can I see the source code, the created pcap, and the expected pcap @FutureSharks ?

stryngs avatar Dec 03 '22 07:12 stryngs

@stryngs all those things are already posted/discussed above. This was created 3 years ago, I'm not longer working on the issue 🙂

FutureSharks avatar Dec 05 '22 09:12 FutureSharks

I'll close this issue as @guedou and I don't think this is really a bug, plus attempting to change the behaviour would probably result in (more) hacks.

p-l- avatar Dec 06 '22 12:12 p-l-