Overview of MAC Algorithms, Fuzzing TLS and Finally Exploiting CVE-2016-7054 Part 1/3

Overview of MAC Algorithms, TLS Protocol and CHACHA20-POLY1305 Algorithms

In the upcoming posts I’m going to give an introduction on Openssl CVE-2016-7054 vulnerability and the terminology about this topic. In part 2 we will discuss available tools and techniques and how to actually produce an exploit for this vulnerability, in the 3rd part we will try to enumerate installed Openssl version on our systems and see how we can update software packages that use Openssl like Apache, Nginx and Python.

Intro

Couple of days ago Fortinet published a blog post titled “Analysis of OpenSSL ChaCha20-Poly1305 Heap Buffer Overflow (CVE-2016-7054)“. A vulnerability in Openssl library was disclosed affecting versions 1.1.0a and 1.1.0b described as High-Severity Heap Buffer Overflow. Vulnerable code is located in openssl-OpenSSL_1_1_0a\crypto\evp\e_chacha20_poly1305.c file.

Let’s take a look at it, vulnerable pieces of code is described in the comments below:

//Line No 196
static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                                    const unsigned char *in, size_t len)
{
...
//Line No 241
            } else { /* ciphertext: Decrypt the ciphertext */
                 Poly1305_Update(POLY1305_ctx(actx), in, plen);
                 chacha_cipher(ctx, out, in, plen);
                 in += plen;
                 out += plen; //out points to the end of the buffer where decrypted ciphertext is stored. 
                 actx->len.text += plen;
            }
...
//Line No 293
        Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag
                                                        : temp); //Generate MAC from the ciphertext
        actx->mac_inited = 0;

        if (in != NULL && len != plen) {        /* tls mode */
            if (ctx->encrypt) {
                memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
            } else {
                if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) { 
                /* If the generated MAC doesn't match the one sent along with ciphertext...
                   Clear the buffer where ciphertext was stored, but notice that 'out' points
                   to the end of the buffer ** So extra space from heap will be cleared **
                */
                    memset(out, 0, plen);
                    return -1;
                }
            }
        }
        else if (!ctx->encrypt) {
            if (CRYPTO_memcmp(temp, actx->tag, actx->tag_len))
                return -1;
        }
    }
    return len;
}

In order to have a better insight on this issue, let’s review what MACs are and how they are implemented.

What’s a MAC (Message Authentication Code) ?

In an encryption scheme say AES in CBC mode, we only have Confidentiality provided by the algorithm. Let’s define some terms before we go any further:

  • Confidentiality: The ability to prevent eavesdroppers from discovering the plaintext message, or information about the plaintext message.
  • Integrity: The ability to prevent an active attacker from modifying the message without the legitimate users noticing.
  • Authenticity: The ability to prove that a message was generated by a particular party, and prevent forgery of new messages. This is usually provided via a Message Authentication Code (MAC). Note that authenticity automatically implies integrity.

This means that using a cipher like AES in CBC mode there’s no guarantee that the message hasn’t been tampered with in transit and there’s no guarantee that it hasn’t been forged by another party or in other terms, it only defends against passive attackers. A MAC is a piece of additional information sent along with the message in order to authenticate it and prevent tampering. So by adding a MAC to an encryption scheme we can provide “Authenticity” and “Integrity” in addition to confidentiality.

Now  let’s assume we have the actual message (plaintext) which is going to be encrypted and the MAC generated from the message, in order to send these two pieces of information we have to make a choice to:

Encrypt-then-MAC

Encrypt-and-MAC

MAC-then-encrypt

Encrypt-then-MAC

Encrypt-and-MAC

MAC-then-Encrypt

 

Encrypt-then-MAC (EtM)

In this scheme we encrypt the message, compute a MAC from the encrypted message and append it to the ciphertext we have already generated as used in IPSEC.

Encrypt-and-MAC (E&M)

In this scheme we compute the mac from the cleartext message, encrypt the cleartext message and append the MAC at the end of the encrypted message as used in SSH.

MAC-then-encrypt (MtE)

In this scheme we compute a MAC from the cleartext message, append it to the message and then encrypt the whole thing as used in TLS.

There’s a long debate on the internet about which one’s a better option and which one’s more prone to vulnerabilities. Without going deep into the pros and cons of each of these methods, I refer you to read further at https://crypto.stackexchange.com/a/205/30687. But briefly Encrypt-then-MAC mode is theoretically better since it makes it easier to prove its security, the MAC prevents the attacker from feeding invalid ciphertexts so it protects against chosen ciphertext attacks and since the MAC is generated from the encrypted message there’s no way it will reveal and leak information about the plaintext, but this scheme is harder to implement correctly.

Generating the MAC

A MAC algorithm is sometimes called a keyed hash, because one of the ways with which we can implement the MAC is using hash functions like HMAC. We can also use block ciphers in modes like CBC-MAC. In the figure below we can see the sender generating a MAC, sending it along with the cipher text and then the receiver verifying it.

MAC

TLS Ciphersuites with AES-GCM or CHACHA20-POLY1305 have integrated MAC algorithms whereas other suites like AES-CBC ones use HMAC as their MAC generation algorithm. Moving on to the next important topic, let’s review what CHACHA20 and POLY1305 algorithms are.

CHaCHa20 Stream Cipher and Poly1305 Authenticator

RFC 5739 defines CHACHA20 and POLY1305 algorithms. CHACHA20 is the stream cipher and POLY1305 is the authenticator. These two algorithms are combined in TLS to form AEAD (Authentication Encryption with Additional Data). There are two main points that make these algorithms important, first one is that AES has become the golden standard in encryption to where it is our sole solution for encryption and its replacement is 3DES which is old. There are even hardware implementations for AES that accelerate its computations making it a better choice over other algorithms but some of the mobile devices lack this feature. Now at the depicted state, if a vulnerability is found in AES our plan B may not be so clear, so for these reasons it may be wise to support some replacements for AES.

ChaCha20

ChaCha20 is a refinement of Salsa20 algorithm and uses 256-bit key. ChaCha20 successively calls the ChaCha20 block function, with the same key and nonce, and with successively increasing block counter parameters.  ChaCha20 then serializes the resulting state by writing the numbers in little-endian order, creating a keystream block. This stream is then XORed with the plaintext to generate the ciphertext.

ChaCha20 takes as input:

  1. 256-bit key
  2. 32-bit initial counter
  3. 96-bit nonce (IV)
  4. Arbitrary length plain text

And the output is the ciphertext with the same length as plaintext.

Poly1305

Poly1305 is a one-time authenticator and takes as input:

  1. 32-byte one-time key
  2. a message

And outputs a 16-byte tag used to authenticate the message. Poly1305 uses AES to encrypt the nonce but AES can be replaced with an arbitrary keyed function as the paper states.

So using ChaCha20-Poly1305 yields us:

Cipher text (Same length as Plain text) 16-byte tag

 

At this point we know enough about the basics and we can take it further from here. The next step would be to try and trigger the vulnerable code by generating a TLS message with a faulty tag.

TLS Messages

I’ve discussed the messages used in TLS protocol before, to review them let’s look at this diagram:

Screen Shot 2016-07-17 at 11.51.50 PMWe send a ClientHello with a cipher suite that uses ChaCha20 and Poly1305 e.g DHE-RSA-CHACHA20-POLY1305-SHA256. If the server supports this cipher suite it will come back with a server hello, else it will throw a handshake failure alert (ChaCha20-Poly1305 support was introduced in OpenSSL 1.1.0). After key exchange and finish messages we can send our application data and this is where we want to send a bad MAC to trigger the vulnerability. In the upcoming blog posts I’ll show you how we can achieve this goal.