DOS attack on quagga with AS4 patch

17.10.2007, 09:15h CEST This mail tells about security holes in AS4 patched quaggas. I put my personal assessments between horizontal lines down below.

The patches, released Fri 19.10.2007, 17:00h CEST

For any patched quagga version before v09 (i.e. v01-v07), please use

quagga-as4-DOSpre-9.patch

and for a quagga patched with version 09 use

quagga-as4-DOSv9.patch

as add-on patch in order to get rid of the holes this advisory points out.

Be aware that you will encounter offsets with the pre-9 patch, but as log as nothing is rejected you will be fine. I tested a v07 patched version only - and there I had a hundered and some lines as offset.

The advisory

From: Mu Security Research Team
Subject: Quagga BGP with AS4 patch DoS
Date: Tue, 16 Oct 2007 16:02:12 -0700
To: Juergen Kammer

We found two DoS issues running Quagga 0.99.9 with AS4 patch v9.  In  
both cases, AS4 is disabled on the peer (i.e., we didn't send the AS4  
capability).

If you have questions, we would be happy to help. Once you have had a  
chance to
fix the problem, let us know so that we can release an advisory.

I'm Cc'ing Paul because we know he's integrating the patch into  
Quagga HEAD.

Regards,
Mu Security Research Team


1) UPDATE with malformed AS4_PATH attribute

Sending an UPDATE with a malformed AS4_PATH can cause a crash when  
Quagga
references a NULL pointer. When an AS4_PATH attribute is read, the AS  
path data
is parsed and stored and a flag is set to note the data is present
(bgp_attr_as4_path() in bgp_attr.c). However, if parsing fails, the  
path data is
set to NULL but the flag is still set. Parsing fails when the  
attribute length
is not a multiple of 2 (aspath_parse() in bgp_aspath.c). Later, in
bgp_attr_path(), the number of AS4_PATH hops is counted and the NULL  
path data
is dereferenced.


(gdb) bt
#0  0x0002167c in aspath_count_hops (aspath=0x0) at bgp_aspath.c:551
#1  0x0002b0bf in bgp_attr_parse (peer=0x181d600, attr=0xbffff050,  
size=152, mp_update=0xbffff02c, mp_withdraw=0xbffff020) at bgp_attr.c: 
1698
#2  0x00074860 in bgp_update_receive (peer=0x181d600, size=156) at  
bgp_packet.c:1604
#3  0x00078571 in bgp_read (thread=0xbffff204) at bgp_packet.c:2435
#4  0x000df4c5 in thread_call (thread=0xbffff204) at thread.c:1051
#5  0x00002853 in main (argc=14, argv=0xbffff30c) at bgp_main.c:323

(gdb) f 1
#1  0x0002b0bf in bgp_attr_parse (peer=0x181d600, attr=0xbffff050,  
size=152, mp_update=0xbffff02c, mp_withdraw=0xbffff020) at bgp_attr.c: 
1698
1698    has as many hops as asnums

(gdb) list
1693     prepend them to AS4_PATH so that
1694               *       num_new = numas_in_aspath
1695               *      the resulting thing is our AS_PATH
1696               *  An AS_SET or AS_CONFED_SET is one hop
1697               *  every other thing has as many hops as asnums
1698               */
1699              int hopnumdiff = aspath_count_hops( attr->aspath )  
- aspath_count_hops( as4_path );
1700
1701              if ( BGP_DEBUG(as4, AS4))
1702                zlog_debug (

(gdb) p as4_path
$6 = (struct aspath *) 0x0

2) UPDATE with sole AS4_AGGREGATOR attribute

Sending an UPDATE with only an AS4_AGGREGATOR attribute can cause a  
crash when
dereferences a NULL pointer. When Quagga receives an AS4_AGGREGATOR,  
but not an
AS_AGGREGATOR, it copies the aggregator AS to attr->extra->aggregator_as
(bgp_attr_parse() in bgp_attr.c). The field attr->extra will be NULL  
if it
hasn't by allocated by calling bgp_attr_extra_get(). One scenario  
when this can
happen is when AS4_AGGREGATOR is the sole attribute received.

(gdb) bt
#0  0x0002af83 in bgp_attr_parse (peer=0x181d600, attr=0xbffff050,  
size=11, mp_update=0xbffff02c, mp_withdraw=0xbffff020) at bgp_attr.c: 
1663
#1  0x00074868 in bgp_update_receive (peer=0x181d600, size=15) at  
bgp_packet.c:1604
#2  0x00078579 in bgp_read (thread=0xbffff204) at bgp_packet.c:2435
#3  0x000df4cd in thread_call (thread=0xbffff204) at thread.c:1051
#4  0x00002833 in main (argc=14, argv=0xbffff30c) at bgp_main.c:323

(gdb) list
1658                   * AGGREGATOR in that case
1659                   */
1660                  if ( BGP_DEBUG(as4, AS4))
1661                    zlog_debug (
1662                          "[AS4] %s BGP not AS4 capable peer send  
AS4_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with  
AS_TRANS had been there", peer->host);
1663                  attr->extra->aggregator_as = as4_aggregator;
1664                  /* sweep it under the carpet and simulate a  
"good" AGGREGATOR */
1665                  SET_BITMAP (seen, BGP_ATTR_AGGREGATOR);
1666                  attr->flag |= (ATTR_FLAG_BIT  
(BGP_ATTR_AGGREGATOR));
1667                }

(gdb) p attr->extra
$2 = (struct attr_extra *) 0x0
  • This affects only version 9 of the patch.
  • In real life: If an AS4 speaker sends an AS4_AGGREGATOR it will also send an AS_AGGREGATOR, so the situation will only happen if an AS_AGGREGATOR is filtered away somewhere or an AS4_AGGREGATOR is added without an AS_AGGREGATOR. May happen only by a wrong AS4 implementation - or deliberately by bad guys. As in 1), there have been no reports of something happening like this until now.
  • Note also that this may be caused by remote BGP sites which are not directly peering with the AS4 quagga which crashes.