image n/a

Detecting Promiscuous Mode NIC

I was recently asked the question: if you had a packet crafting tool and suspected a machine on the network was running in promiscuous mode - how would you detect it? At the time I wasn't sure if I was expected to come up with an ingenious method for doing this, or if it was just asked to measure 1) if I knew what "promiscuous mode" was, 2) if I knew the difference between promiscuous mode and normal mode and 3) if I could at least come up with a semi-rational method of detection.

Regardless of why I was asked, the answer was a little uncertain. My initial response had something to do with spoofing the destination IP address of the machine that we suspected to be in promiscuous mode. This turned out to be a not-so-correct answer.

A card in promiscuous mode ignores the destination MAC address and sends all packets received to the kernel. If we want to detect which card is sniffing the network, we would need to fool it into responding to some stimuli we place on the wire. The response would need to prove that our stimuli made it past some particular boundary not accessible when the NIC is not in promiscuous mode. Opposed to my initial belief, if a packet is sent to the destination with an IP that is not one of it's own - sure, it may make it past the harware filter and up to the kernel, but the kernel wouldn't reply to an echo request addressed to an IP that it did not own.

So, the solution would be to make sure the destination IP is indeed accurate for the machine suspected of being in promiscuous mode. If you're doing a general scan of the network, this would need to be done once for each possible IP within the range. The technique would be to send a packet to every transport layer address; while specially crafting the MAC address so that it's value is certainly non existent on your network. We could go by the following pseudo code:

#!/usr/bin/perl 
$class_c_netblock='192.168.1.';
$fake_dst_mac='01:01:01:01:01'; 
$true_src_mac='00:E0:4C:A3:6F:57'; 
$true_src_ip='192.168.1.50'; 
foreach $fourth_octet (1..254) {
  # send_arp(to_ip, to_mac, from_ip, from_mac); 
  $to_ip = "$class_c_netblock" . "$fourth_octet"; 
  send_arp($to_ip, $fake_dst_mac, $true_src_ip, $true_src_mac); 
  ($from_ip, $from_mac) = read_arp_reply();
  print STDOUT "$from_ip is running in promiscuous mode...\n";  
}

OK, so maybe that wasn't so pseudo - the only thing missing is the send_arp and read_arp_reply functions which could probably be done in a bit of IO SOCKET code [Update 2005-12-12: IO SOCKET would not work because it only applies to TCP and UDP]. In order to prove how my original thought was wrong, we wouldn't want to spoof the destination IP address when attempting to detect a promiscuous ethernet card. In fact, the destination IP address should be accurate for for the machine we suspect to be sniffing the network. We would want introduce an ARP (A) packet to the network - destined for the true IP address but with an incorrect MAC address. By this mechanism, the promiscuous card would ignore the fact that the MAC address is not it's own, pass the packet up to the kernel, which would then invoke a response to the packet since it was destined for an IP address that it owns.

Here is an example that assumes the suspected machine has an IP address of 192.168.1.1 and a true MAC address of 00:0C:41:E9:2B:9D. Your machine has a true IP of 192.168.1.50 and a true MAC of 00:E0:4C:A3:6F:57. Imagine you execute the following commands on your machine:

Update 2005-12-12: Nemesis is a packet crafting tool with a built-in ARP module. It can be obtained from (The Nemesis Sourceforge Page).

# tcpdump -i eth0 -e arp and host 192.168.1.50 > pcap &

# nemesis arp \
-S 192.168.1.50 \      # Your IP
-D 192.168.1.1 \       # Suspected Promiscuous IP
-M 01:01:01:01:01:01   # Non-existent MAC (on your network at least)

# cat pcap
00:50:2c:05:6b:a9 > 01:01:01:01:01:01, arp who-has 192.168.1.1 tell 192.168.1.50
00:0c:41:e9:2b:9d > 00:50:2c:05:6b:a9, arp reply 192.168.1.1 is-at 00:0c:41:e9:2b:9d

This shows that although we directed a packet at a MAC address that surely does not exist on our network, a response *was* received. The TCP/IP stack of the machine in promiscuous mode was successfully fooled into thinking that it had the MAC address of 01:01:01:01:01.

As further rebuttal of my original idea, here is another attempt at detecting promiscuous mode by entering a non-existent destination IP address:

# nemesis arp \
-S 192.168.1.50 \      # Your IP
-D 192.168.1.77 \      # Random destination IP
-M ff:ff:ff:ff:ff:ff   # Broadcast

# [repeat above command 3 more times]

# cat pcap
00:50:2c:05:6b:a9 > ff:ff:ff:ff:ff:ff arp who-has 192.168.1.77 tell 192.168.1.50
00:50:2c:05:6b:a9 > ff:ff:ff:ff:ff:ff arp who-has 192.168.1.77 tell 192.168.1.50
00:50:2c:05:6b:a9 > ff:ff:ff:ff:ff:ff arp who-has 192.168.1.77 tell 192.168.1.50
00:50:2c:05:6b:a9 > ff:ff:ff:ff:ff:ff arp who-has 192.168.1.77 tell 192.168.1.50

The point is that there is no response on this occassion. Although the owner of this network (me) can vouch for the fact that there *are* machines on the network in promiscuous mode, this particular test does not reveal any proof. It is not successfull in invoking a response or any overt indication that any machines are sniffing the wire.

So I have to give (Andy) credit for this theory, because he mentioned it probably about six months ago. Also (Matt) seemed to be on the same page during earlier discussion. It should be noted that one suggestion mentioned echo requests with specially crafted destination MAC addresses would work. I agree, but in the case that echo replies are filtered outbound on the suspected system, the above methodology would not work. Theoretically, TCP and UDP packets would work just fine also, however ARP is the best possibility (seriously, who filters outbound ARP on an ethernet?). In searching (Google), [how ironic], it turns out there are other similar results on (ARP for Promiscuous Detection).

Art of Memory Forensics

Malware Analyst's Cookbook

Site design and layout with umm...a bash shell. Graphic by (Aaron Bieber)
Unless otherwise noted, this work is licensed with (Creative Commons Attribution License).