FortiGuard Labs Threat Research

Analysis of OpenSSL ChaCha20-Poly1305 Heap Buffer Overflow (CVE-2016-7054)

By Dehui Yin | November 23, 2016

A High-Severity Heap Buffer Overflow vulnerability was recently fixed in a patch  by Openssl Project.  This vulnerability affects the remote SSL servers that support the ChaCha20-Poly1305 cipher suite, and can be exploited to crash the SSL service.

This High-Severity Heap Buffer Overflow vulnerability (CVE-2016-7054) is caused by an error when the ChaCha20-Poly1305 cipher suite is decrypting large amounts of application data. We will examine the root cause of this vulnerability in this post.

The ChaCha20-Poly1305 cipher suite is a new form of encryption which can improve mobile performance. It was introduced as a new feature in OpenSSL 1.1.x, and is supported by TLS ver1.2. The application data encrypted by ChaCha20-Poly1305 is composed of two parts: ciphertext encrypted by the ChaCha20 cipher, and message authentication code (MAC). MAC is generated by Poly1305 to verify the integrity and authenticity of the ciphertext, and it is 16-bytes fixed.

The vulnerability is triggered by an error when verifying the MAC. If the MAC is incorrect, the "ChaCha20_Poly1305_Cipher" function clears the buffer used to store the decrypted ciphertext via "memset." However, an incorrect buffer pointer passed to "memset" clears the import HEAP structure and causes the crash.

The following code snippet was taken from OpenSSL 1.1.0a. (Comments added by me have been highlighted.)

e_chacha20_poly1305.c:

196      static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,

197                                          const unsigned char *in, size_t len)

198      {

199          EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);

             //Set "plen" as the length of ciphertext

200          size_t rem, plen = actx->tls_payload_length;

          ....

                    

241                  } else {                            /* ciphertext */

242                      Poly1305_Update(POLY1305_ctx(actx), in, plen);

                         //Decrypt the ciphertext

243                      chacha_cipher(ctx, out, in, plen);

244                      in += plen;

                         //Adjust the buffer used to store decrypted ciphertext. It will point to the end of the decrypted ciphertext

245                      out += plen;

246                      actx->len.text += plen;

          ....

                         

                     //Generate the correct MAC for the ciphertext

293              Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag

294                                                              : temp);

295              actx->mac_inited = 0;

296     

297              if (in != NULL && len != plen) {        /* tls mode */

298                  if (ctx->encrypt) {

299                      memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);

300                  } else {

                         //Compare the MAC in the TLS message with the MAC generated above

301                      if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {

                         //If the MAC in the TLS message doesn't match, clear the buffer used to store decrypted ciphertext. Here, "out" points to the end of the  buffer, which is incorrect. It should point to the beginning of the buffer. "memset" will clear the memory, followed by the end of buffer according to the size argument "plen". If "plen" is large enough, the heap structure will be cleared.

302                          memset(out, 0, plen);

303                          return -1;

304                      }

The crash occurs when OpenSSL frees the buffer. Following is an image of a portion of the affected OpenSSL server:

Please note that authentication is NOT required to exploit this vulnerability.

IPS Signature

Fortinet released IPS signature Openssl.ChaCha20.Poly1305.Heap.Buffer.Overflow to address this vulnerability.