OpenSSL严重安全漏洞CCS

来源:互联网 发布:python做web性能测试 编辑:程序博客网 时间:2024/04/29 08:39

     继之前爆出的“心脏出血”漏洞后,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漏洞!


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



0 0
原创粉丝点击