kern/60293: FreeBSD arp poison patch

Roman Y. Bogdanov brj at vzletka.net
Tue Dec 16 01:20:16 PST 2003


>Number:         60293
>Category:       kern
>Synopsis:       FreeBSD arp poison patch
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Tue Dec 16 01:20:06 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Roman Y. Bogdanov
>Release:        FreeBSD 4.9 release
>Organization:
brj.pp.ru
>Environment:
n/a
>Description:
There is well known problem arp poisoning problem in FreeBSD. If 
arp reply is received without request FreeBSD logs error 
into syslog, but changes arp table entry. It makes possibility 
for local atacker to change arp cache entry. In network this 
behaviour can only occure when adapter changes it's MAC address. 

This like a linux kernel patch (2.4.18 and .19 tested) to resisting ARP spoofing - http://groups.google.com/groups?selm=001901c28c23%2414c08320%240101fea9%40r66.ru&oe=UTF-8&output=gplain
>How-To-Repeat:
n/a
>Fix:
Attached is patch to check old MAC address before changing 
arp entry by sending unicast arp request to this MAC. If old MAC 
replies, no changes to arp table is made and attack is logged.

[PATCH]

--- if_ether.c.old	Tue Dec  2 19:57:08 2003
+++ if_ether.c	Wed Dec  3 10:41:38 2003
@@ -40,6 +40,10 @@
  *	add "inuse/lock" bit (or ref. count) along with valid bit
  */
 
+/*
+ * ARP-posion Antidote code (c) 2003 by Bert <bert at furry.ru>
+ */
+
 #include "opt_inet.h"
 #include "opt_bdg.h"
 
@@ -82,6 +86,10 @@
 static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
 static int arpt_down = 20;	/* once declared down, don't send for 20 sec */
 
+static int arp_secure = 1;
+static int arpt_debug = 0;
+
+
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
 	   &arpt_prune, 0, "");
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 
@@ -96,6 +104,9 @@
 	struct	rtentry *la_rt;
 	struct	mbuf *la_hold;		/* last packet until resolved/timeout */
 	long	la_asked;		/* last time we QUERIED for this addr */
+	long	la_ack;			/* Arp reply acknowledgement flag */	
+        u_char  check_eth[ETHER_ADDR_LEN]; /* MAC address, before it changing */
+	struct in_addr	check_ip;
 #define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
 };
 
@@ -115,6 +126,14 @@
 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
 	   &arp_proxyall, 0, "");
 
+/* sysctl arp antidote variable. Default is "on" */
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, arp_antidote, CTLFLAG_RW,
+	   &arp_secure, 0, "");
+	   
+/* sysctl arp debug variable. Default is "off" */
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, arp_debug, CTLFLAG_RW,
+	   &arpt_debug, 0, "");
+
 static void	arp_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
 static void	arprequest __P((struct ifnet *,
 			struct in_addr *, struct in_addr *, u_char *));
@@ -663,14 +682,73 @@
 			    ifp->if_name, ifp->if_unit);
 		    goto reply;
 		}
+		
+		/* Print announced packet if debug is enabled */
+		if (sdl->sdl_alen && arpt_debug) {
+                  log(LOG_INFO, "arp: Got MAC address %*D from %s via %s%d\n", 
+		      ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+		      inet_ntoa(isaddr),
+		      ifp->if_name, ifp->if_unit);
+		}
+		
+		/* Check possible reply with old MAC-address*/
+		if (arp_secure && rt->rt_expire && 
+		    sdl->sdl_alen && la->la_ack == 1 && 
+		    !bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) 
+		{
+		  /* Got old MAC address. Check it with saved */
+		  if (!bcmp(ar_sha(ah), la->check_eth, sdl->sdl_alen)) {
+		    /* Addresses are equal. MAC address verified */
+		    if (arpt_debug)
+                      log(LOG_INFO, "arp: MAC address %*D from %s verified.\n",
+		          ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+		          inet_ntoa(isaddr));
+		    la->la_ack = 0;
+		  } else {
+		    /* Make an arp entry "static" */
+		    rt->rt_expire = 0;
+		    /* Reply with another MAC */
+                    log(LOG_ERR, "arp: ARP poison detected!, attacker from %*D trying to infect %*D (%s) in my ARP table!\n",
+		      sdl->sdl_alen, (u_char *)&la->check_eth, ":",
+		      sdl->sdl_alen, (u_char *)ar_sha(ah), ":",
+		      inet_ntoa(la->check_ip));
+		      
+		    /* Clear cached MAC */
+		    bzero(&la->check_eth, sizeof(la->check_eth));
+		    la->la_ack = 0;
+                    m_free(m);
+                    return;
+		  }
+		}
+		
 		if (sdl->sdl_alen &&
 		    bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
-			if (rt->rt_expire)
-			    log(LOG_INFO, "arp: %s moved from %*D to %*D on %s%d\n",
-				inet_ntoa(isaddr),
-				ifp->if_addrlen, (u_char *)LLADDR(sdl), ":",
-				ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
-				ifp->if_name, ifp->if_unit);
+			if (rt->rt_expire) {
+			    if (arp_secure) {
+                              if (la->la_ack == 0) {
+			        if (arpt_debug)
+                                  log(LOG_INFO, "arp: Got new MAC address %*D from %s (%s%d). Now verifying.\n",
+				      ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+				      inet_ntoa(isaddr),
+				      ifp->if_name, ifp->if_unit);
+				/* Check old MAC address for alive */
+                                arprequest(ifp, &myaddr, &isaddr, IF_LLADDR(ifp));
+				(void)memcpy((u_char *)&la->check_eth, (u_char *)ar_sha(ah), sdl->sdl_alen);
+				la->check_ip.s_addr = isaddr.s_addr;
+				
+                                la->la_ack++;
+				la->la_asked++;
+                                m_free(m);
+                                return;
+			      }
+			    } else {
+			       log(LOG_INFO, "arp: %s moved from %*D to %*D on %s%d\n",
+			          inet_ntoa(isaddr),
+			  	  ifp->if_addrlen, (u_char *)LLADDR(sdl), ":",
+				  ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
+				  ifp->if_name, ifp->if_unit);
+			    }
+			}
 			else {
 			    log(LOG_ERR,
 				"arp: %*D attempts to modify permanent entry for %s on %s%d\n",

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list