From owner-freebsd-net Fri Feb 22 2:26:45 2002 Delivered-To: freebsd-net@freebsd.org Received: from rwcrmhc54.attbi.com (rwcrmhc54.attbi.com [216.148.227.87]) by hub.freebsd.org (Postfix) with ESMTP id 5E5E537B400 for ; Fri, 22 Feb 2002 02:26:31 -0800 (PST) Received: from blossom.cjclark.org ([12.234.91.48]) by rwcrmhc54.attbi.com (InterMail vM.4.01.03.27 201-229-121-127-20010626) with ESMTP id <20020222102626.SMVI1214.rwcrmhc54.attbi.com@blossom.cjclark.org> for ; Fri, 22 Feb 2002 10:26:26 +0000 Received: (from cjc@localhost) by blossom.cjclark.org (8.11.6/8.11.6) id g1MAQQj83932 for net@freebsd.org; Fri, 22 Feb 2002 02:26:26 -0800 (PST) (envelope-from cjc) Date: Fri, 22 Feb 2002 02:26:26 -0800 From: "Crist J. Clark" To: net@freebsd.org Subject: TCP Connections to a Broadcast Address Message-ID: <20020222022626.A83807@blossom.cjclark.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5i X-URL: http://people.freebsd.org/~cjc/ Sender: owner-freebsd-net@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org BSD-based TCP/IP code have a bug with respect to creating TCP connections to a broadcast address. This bug can potentially be a security vulnerability when firewall administrators assume that the TCP implementation works correctly and does not block broadcast addresses. The Standard: TCP connections are only valid when the destination address is a unicast address. That is, the destination must not be a multicast or broadcast address. One place this is clearly specified in the Standards is RFC 1122 (everyone's very most favorite RFC), 4.2.3.10 Remote Address Validation ... A TCP implementation MUST silently discard an incoming SYN segment that is addressed to a broadcast or multicast address. The Bug: Uncorrected BSD-based TCP implementations do not actually check if the destination IP address is a broadcast address. Rather, the packet's link layer address is checked. Here is the code from FreeBSD's tcp_input.c, * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received * packet with M_BCAST not set. * * Packets with a multicast source address should also * be discarded. */ if (m->m_flags & (M_BCAST|M_MCAST)) goto drop; #ifdef INET6 if (isipv6) { if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) goto drop; } else #endif if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || ip->ip_src.s_addr == htonl(INADDR_BROADCAST)) goto drop; The comment in the code reveals the reason for the mistake. The authors assume that no one would accidentally or maliciously break the rules. One can easily send packets with a unicast link-layer address, but containing an IP broadcast address. No check is made in the above code for such a pathological situation. A Demonstration: There are many ways to take advantage of this bug. Here is one easy way that will not interfere with normal operations of the test network: 1) On the victim machine add an alias for an unused network, # ifconfig if0 inet 192.0.2.1 alias 2) On the attack machine, which must be local to the victim on the interface configured in step (1), add a route(8), # route add 192.0.2.0/24 3) Now from the attacker, try to establish a TCP connection to the victim's broadcast address on any port that might be listening on the victim, # ssh The connection should succeed. Another slightly scarier attack, since it doesn't require any changes to the victim host, is to just change the attacker's idea of the netmask, making the network "bigger," so that the broadcast address of the network now looks like a unicast to the attacker. But remember this might break some things on the attacker while the network is misconfigured. The Vulnerability: This creates a potential security vulnerability. The firewall administrator may assume that it is not possible to establish TCP connections to a broadcast address and therefore may not protect it adequately. This vulnerability is mitigated by a number of factors: - If the firewall follows a more secure explicitly-pass-default-deny policy, this probably will not be a problem. - An attacking or misconfigured host must be local to the victim. - The attacking host can only connect to broadcast addresses on the local interface. One issue may exacerbates the problem for ipfw(8) users. The 'me' destination in an ipfw(8) rule does NOT match the interface's broadcast address. So, deny tcp from any to me via if0 Would not block a TCP connection to the broadcast address on if0. Using rules like the above on a firewall machine meant to allow forwarded traffic through the external interface, but not allow direct connections to the firewall is probably not uncommon, but it creates a vulnerable configuration. The Fix: Adding an in_broadcast() check trivially fixes the problem. Here is a patch (which fixes the comment too), Index: src/sys/netinet/tcp_input.c =================================================================== RCS file: /export/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.146 diff -u -r1.146 tcp_input.c --- src/sys/netinet/tcp_input.c 4 Jan 2002 17:21:27 -0000 1.146 +++ src/sys/netinet/tcp_input.c 17 Feb 2002 12:54:39 -0000 @@ -798,11 +798,10 @@ } /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN - * in_broadcast() should never return true on a received - * packet with M_BCAST not set. - * - * Packets with a multicast source address should also - * be discarded. + * + * It is possible for a malicious (or misconfigured) + * attacker to send unicast link-layer packets with a + * broadcast IP address. Use in_broadcast() to find them. */ if (m->m_flags & (M_BCAST|M_MCAST)) goto drop; @@ -815,7 +814,8 @@ #endif if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || - ip->ip_src.s_addr == htonl(INADDR_BROADCAST)) + ip->ip_src.s_addr == htonl(INADDR_BROADCAST) || + in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) goto drop; /* * SYN appears to be valid; create compressed TCP state Actions: I notified security-officer@freebsd.org on Feburary 17th. From examining NetBSD and OpenBSD source code, they appear to have the same flaw. security-offier@ at each was notified at the same time and provided with appropriate patches. I have been unable to actually test the vulnerabilities on an operational NetBSD or OpenBSD system. I have not heard anything from either NetBSD or OpenBSD, and no changes have been committed to their code. rwatson requested I post the above patch to net@ for community review and feedback. So, if no one has any problems with this fix, I will commit it. I have approval to add the fix to the RELENG_4_? security branches once the final fix has been reviewed. Some other remarks about the checks we see above: - The IN_MULTICAST() checks of the source address should not be necessary. Multicast source addresses are never valid for IP datagrams and should be rejected in the network layer. The same applies to the check for multicast source addresses in IPv6. - Since IPv6 does not have broadcasts, it should not be vulnerable provided the multicast check of the destination address is robust. I have not examined the IPv6 code in this respect. After the fix to FreeBSD is made and other *BSD's have ample time to responde, I do plan to send a quick note on the subject to Bugtraq. Thanks for reading. I look forward to comments on the fix. -- Crist J. Clark | cjclark@alum.mit.edu | cjclark@jhu.edu http://people.freebsd.org/~cjc/ | cjc@freebsd.org To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message