Cyrus SASL library buffer overflows

From: Timo Sirainen (tssat_private)
Date: Mon Dec 09 2002 - 11:25:08 PST

  • Next message: securityat_private: "Security Update: [CSSA-2002-SCO.43] UnixWare 7.1.1 Open UNIX 8.0.0 : closed file descriptor race vulnerability"

    These overflows are found at least in version 2.1.9, none of them are
    present in 1.5.28. 2.1.10 was just released which fixed the problems.
    
    Note that besides the Cyrus project itself, the SASL library is also used
    by Postfix-TLS patch, OpenLDAP and probably some other servers.
    
    Problem 1
    ---------
    
    Insufficient buffer length checking in user name canonicalization may allow
    attacker to execute arbitrary code on servers using Cyrus SASL library.
    Client side library also has the bug but since the user name is asked from
    the local user, there's probably not many applications that care about it,
    except maybe webmails and the like. This overflow only happens if default
    realm is set.
    
    Exploiting may not be too easy though, since you can only write
    "@default.realm.name" to limited space in heap past the buffer, depending
    on how long user name is allowed. With postfix this is around 2048 BASE64
    encoded bytes (around 1500 bytes) by default. Postfix uses $myhostname as
    default realm name.
    
    We can overflow two different buffers at the end of sasl_conn_t structure:
    
      char user_buf[CANON_BUF_SIZE+1], authid_buf[CANON_BUF_SIZE+1];
    
    sasl_conn_t is malloc()ed, so the most obvious exploit could happen with
    modifying malloc headers. Since we can use only few specific characters,
    the possibility to exploit is very system dependant.
    
    Problem 2
    ---------
    
    LDAP authentication with saslauthd doesn't allocate enough memory when it
    needs to escape characters '*', '(', ')', '\' and '\0' in username and
    realm. This should be easily exploited with glibc's malloc implementation.
    
    Problem 3
    ---------
    
    Log writer might not have allocated memory for the trailing \0 in
    message. Probably hard to exploit, although you can affect the logging
    data with at least anonymous authentication.
    
    patch
    -----
    
    If you need for some reason.
    
    diff -ru cyrus-sasl-2.1.9-old/lib/canonusr.c cyrus-sasl-2.1.9/lib/canonusr.c
    --- cyrus-sasl-2.1.9-old/lib/canonusr.c	2002-09-16 21:37:20.000000000 +0300
    +++ cyrus-sasl-2.1.9/lib/canonusr.c	2002-12-05 06:18:36.000000000 +0200
    @@ -306,6 +306,7 @@
         /* Now copy! (FIXME: check for SASL_BUFOVER?) */
         memcpy(out_user, begin_u, MIN(ulen, out_umax));
         if(sconn && u_apprealm) {
    +        if(ulen >= out_umax) return SASL_BUFOVER;
     	out_user[ulen] = '@';
     	memcpy(&(out_user[ulen+1]), sconn->user_realm,
     	       MIN(u_apprealm-1, out_umax-ulen-1));
    diff -ru cyrus-sasl-2.1.9-old/saslauthd/lak.c cyrus-sasl-2.1.9/saslauthd/lak.c
    --- cyrus-sasl-2.1.9-old/saslauthd/lak.c	2002-08-01 22:58:24.000000000 +0300
    +++ cyrus-sasl-2.1.9/saslauthd/lak.c	2002-12-05 07:43:34.000000000 +0200
    @@ -279,7 +279,7 @@
     	char *buf;
     	char *end, *ptr, *temp;
     
    -	buf = malloc(strlen(s) * 2 + 1);
    +	buf = malloc(strlen(s) * 3 + 1);
     	if (buf == NULL) {
     		return LAK_NOMEM;
     	}
    @@ -358,7 +358,8 @@
     		if( *buf == '%' ) percents++;
     	}
     
    -	buf=malloc(strlen(lak->conf->filter) + (percents * maxparamlength) +1);
    +	buf=malloc(strlen(lak->conf->filter) +
    +		   (percents * maxparamlength * 3) + 1);
     	if(buf == NULL) {
     		syslog(LOG_ERR|LOG_AUTH, "Cannot allocate memory");
     		return LAK_NOMEM;
    diff -ru cyrus-sasl-2.1.9-old/lib/common.c cyrus-sasl-2.1.9/lib/common.c
    --- cyrus-sasl-2.1.9-old/lib/common.c	2002-09-19 01:07:54.000000000 +0300
    +++ cyrus-sasl-2.1.9/lib/common.c	2002-12-05 08:11:49.000000000 +0200
    @@ -1326,6 +1326,8 @@
         }
       }
     
    +  result = _buf_alloc(&out, &alloclen, outlen+1);
    +  if (result != SASL_OK) goto done;
       out[outlen]=0; /* put 0 at end */
     
       va_end(ap);    
    



    This archive was generated by hypermail 2b30 : Mon Dec 09 2002 - 12:08:49 PST