您的位置:首页 > 运维架构

OpenSSL严重安全漏洞CCS

2014-06-09 23:09 295 查看
继之前爆出的“心脏出血”漏洞后,openSSL再被爆出另一个严重漏洞,最初在开源中国看到文章时把CCS看成了CSS,囧~~

“OpenSSL 的 ChangeCipherSpec 处理再报严重安全漏洞,该漏洞使得攻击者可以拦截恶意中间节点加密和解密数据,同时迫使使用弱密钥的SSL客户端暴露在恶意节点。”

借用文章里的CCS注入的图:



下面翻译漏洞发现者的博客:“我是如何发现CCS注入攻击的”.

原文地址:http://ccsinjection.lepidum.co.jp/blog/2014-06-05/CCS-Injection-en/index.html

什么是CCS注入漏洞

在客户端和服务端握手阶段,OpenSSL协议不合时宜地接受密码更换说明(ChangeCipherSpec :CCS),而产生了该漏洞。而且,从第一个版本的OpenSSL起,这个漏洞就一直存在。

OpenSSL里正常握手过程中,客户端和服务端的消息交换式按照下图流程进行的(参照RFC5246 The Transport Layer Security (TLS) Protocol Version 1.2 §7.3)。



如图,在握手阶段需要两次发送ChangeCipherSpec消息,OpenSSL也确实是按照正确的时间发送CCS,然而,CCS消息却可以在其他时间里被接收。攻击者就可以利用这一行为解密或者修改传输通道里的数据。

发现漏洞有多难

造成CCS漏洞16年没有被发现的原因是OpenSSL实现缺少全面的代码审查(code reviews)。如果审查者有一定的TLS和SSL开发经验,那么他们就应该能自己发现这个问题。

模糊测试也许很有效,但历史经验表明,拥有TLS/SSL开发经验对发现OpenSSL安全问题尤为重要:

CVE-2004-0079漏洞

CVE-2004-0079是Codenomicon发现CCS漏洞,也是第一个CCS漏洞。 之后Fix null-pointer assignment in do_change_cipher_spec()
revealed被加入到OpenSSL中以修补这个漏洞。这个方法保证了CCS只在有新的密码产生后才被接收,然而这个新的密码在服务器端请求连接是就产生了,所有该方法并不能真正地防止CCS注入。

CVE-2009-1386漏洞

DTLS: SegFault if ChangeCipherSpec is received before ClientHello

这个漏洞是因为在DTLS握手阶段太早地接收CCS消息,造成了分段错误。针对CCS时序验证也并没有很好滴被解决。

DTLS fragment retransmission bug

OpenSSL的第
#1950 补丁修改了带漏洞。

DTLS fragment retransmission bug

该补丁增加了对不可预测报文冲排序的验证,解决了DTLS握手中的CCS时序问题。进一步分析该补丁可以发现,一个非计算的主密钥被用来加密,这个值被告知是从未被初始化的内存中读取的,不能使用随机值。然而事实是:这个值是一串空比特序列,如果这个问题被及早发现,这个CCS攻击的可能性将大大降低。

正确实现CCS有多难?

答案是:非常简单! 只需要保证CCS的发送和接收顺序都按照上图中的协议流程进行。然而这里包含了一个意外:CCS消息的序列标识和其他握手消息的序列标识不是同一种类型。RFC的解释如下:

Note:          To help avoid pipeline stalls, ChangeCipherSpec is
an independent SSL Protocol content type, and is not
actually an SSL handshake message.


draft-ietf-tls-ssl-version3-00 §5.5

我认为,这个决定就是导致CCS脆弱性的根源。根据RFC给出的解释,CCS使用独立的序列标识(也就是说CCS不算是真正的SSL握手消息)是为了避免“流水线停顿”(pipeline stall)。这就使得TLS/SSL的握手阶段需要非常复杂的同步机制:首先,OpenSSL协议需要等待握手过程进行到合适的阶段;其次,协议需要去检查握手阶段在结束之前是否接受到CCS消息。

详细地,当接收到CCS消息时,需要检验以下三个情况:(*)

握手过程是否进行到合适阶段,例如是否是在握手结束之前收到
握手过程没有其他片段
下一个消息是否完成

更需要小心的是你还得检查下面两个情况(详见Alert attack.):

没有警告片段
没有心跳片段

RFC估计是想表达出下面两个顾虑:

避免CCS被夹杂在其他握手片段里传输。
为了避免流水线停顿,服务器和客户端都需要发送CCS消息。

我是如何发现这个漏洞的

“心脏出血”漏洞暴露后,大家都在讨论和研究如何避免类似这种的bug,单元测试、代码分析、fork and rewrite cleanly, improve API, not to reinvent malloc, 结合C以外的其他语言进行测试,这些技术都被用来测试OpenSSL的安全性。

ATS就是其中一种比较受欢迎的测试语言。我思考过,用Coq(形式化验证管理系统) 来验证ATS写的TLS/SSL。证明协议的安全性是一个巨大的工作,虽然它不会有助于实现安全,我一直在尝试一些方法能够清楚明了地展示协议实现的正确性。

我的目标是:

解释器(parsers)和输出机(printers)能完美耦合
输出机能被正确实现
状态机的行为用谓词表示

考虑*标识的三个情况,我开始关注CCS上的状态转换,CCS状态转换是状态机里最复杂的部分。

随后,检查当前实现是否正确考虑到这些情况。我发现除了OpenSSL,大多数的实现多多少少都考虑到了。OpenSSL没有考虑这些情况,OpenSSL也就有CCS漏洞!

第一次翻译,有什么不当之处,希望指出。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: