scapy
scapy copied to clipboard
ARP bug where source MAC is 00:00:00:00:00:00
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
Resolves https://github.com/FutureSharks/rpi-security/issues/53
Hi, could you provide the output of the following commands:
>>> conf.route
>>> conf.iface
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'
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?
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?
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?
OK thanks for the capture. It seems that the bug only occurs when .pdst
is your own IP address. Am I right?
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
...
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
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?
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.
@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.
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.
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.
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().
If possible, can I see the source code, the created pcap, and the expected pcap @FutureSharks ?
@stryngs all those things are already posted/discussed above. This was created 3 years ago, I'm not longer working on the issue 🙂
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.