FortiGuard Labs Threat Research
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.