Lucene search

K
hackeroneNyymiH1:1590071
HistoryJun 02, 2022 - 8:12 p.m.

curl: CVE-2022-32208: FTP-KRB bad message verification

2022-06-0220:12:35
nyymi
hackerone.com
39

0.003 Low

EPSS

Percentile

69.5%

Summary:

libcurl handles gss_unwrap GSS_S_BAD_SIG error incorrectly. This enables malicious attacker to inject arbitrary FTP server responses to GSSAPI protected FTP control connection and/or make the client consume unrelated heap memory as a FTP command response.

The defective krb5_decode function is as follows:

static int
krb5_decode(void *app_data, void *buf, int len,
           int level UNUSED_PARAM,
           struct connectdata *conn UNUSED_PARAM)
{
 gss_ctx_id_t *context = app_data;
 OM_uint32 maj, min;
 gss_buffer_desc enc, dec;

 (void)level;
 (void)conn;

 enc.value = buf;
 enc.length = len;
 maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL);
 if(maj != GSS_S_COMPLETE) {
   if(len >= 4)
     strcpy(buf, "599 ");
   return -1;
 }

 memcpy(buf, dec.value, dec.length);
 len = curlx_uztosi(dec.length);
 gss_release_buffer(&min, &dec);

 return len;
}

Note how read_data function will set the buf->size to result of the decode operation as-is without considering possible -1 return code and that size buf->size is of type size_t:

/* Types needed for krb5-ftp connections */
struct krb5buffer {
  void *data;
  size_t size;
  size_t index;
  BIT(eof_flag);
};
static CURLcode read_data(struct connectdata *conn,
                          curl_socket_t fd,
                          struct krb5buffer *buf)
{
  int len;
  CURLcode result;

  result = socket_read(fd, &len, sizeof(len));
  if(result)
    return result;

  if(len) {
    /* only realloc if there was a length */
    len = ntohl(len);
    buf->data = Curl_saferealloc(buf->data, len);
  }
  if(!len || !buf->data)
    return CURLE_OUT_OF_MEMORY;

  result = socket_read(fd, buf->data, len);
  if(result)
    return result;
  buf->size = conn->mech->decode(conn->app_data, buf->data, len,
                                 conn->data_prot, conn);
  buf->index = 0;
  return CURLE_OK;
}

When gss_unwrap returns an error the krb5_decode code attempts to erase the buffer by prefixing the buffer with 599 \0. However, this doesnโ€™t take into account the case that arbitrary number of bytes can be read by read_data function. Hence the buffer may contain multiple lines not just one. The attacker merely needs to find a position in the FTP protocol where ftpcode 599 doesnโ€™t lead to connection termination to take over the GSSAPI protected FTP session control channel. From that point onwards the server responses can be forged by the attacker (but need to be predicted, as the attacker has no direct knowledge of the actual commands sent to the server).

Itโ€™s also notable that the any gss_unwrap error leading to -1 size will lead to sec_recv consuming unallocated heap buffer via buffer_read if the reading application keeps reading more data:

static size_t
buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
  if(buf->size - buf->index < len)
    len = buf->size - buf->index;
  memcpy(data, (char *)buf->data + buf->index, len);
  buf->index += len;
  return len;
}

This can lead to disclosure of confidential information from the heap - depending on application this may reveal application secrets to the user (for example via verbose error messages). This is a local leak however, so this impact is only meaningful if the information in heap is normally hidden from the user.

Impact

  • Injection of arbitrary FTP control channel server responses to supposedly GSSAPI protected FTP session.
  • Potential leak of local heap memory to client.

The practical impact of this vulnerability is rather low, considering the rarity of Kerberos FTP and requirement of either man in the middle or victim connecting to malicious server.