新闻报道

联系我们

  • 联系人:北京炼石网络技术有限公司
  • 电话:010-88459460
  • 地址:北京市海淀区北三环西路32号楼7层0710-1
  • 邮编:100097

您现在的位置: 新闻报道»CGLab技术文章

从掐秒表的拆弹到不成功的握手

浏览:259   日期: 2016-03-28

本文是面向技术人员,特别是软件架构师介绍Padding Oracle攻击的基本原理及其危害,让大家了解密码系统设计的极其复杂性和易错性,哪怕是对于专家而言,进而明白使用标准避免自行设计密码系统的极端重要性。


2016年53日公开的CVE-2016-2107漏洞就是AES-NI代码对于Lucky13论文作者提出的constant time算法第3步实现不当引入的bug,这篇文章炼石网络CGLab将从Padding Oracle Attack历史谈起,对这个漏洞给大家一个本质性的解释,当然我们也会给出此漏洞的应对建议。


1 Padding Oracle Attack的前世今生


分组加密算法通常使用Cipher Block Chaining (CBC) 模式,明文消息的长度一般会小于整个CBC链中的加密块长度,所以加密时在明文消息的末尾一般会添加一些字节使明文和密文长度对齐,这些加密时添加的字节叫做padding字节,CBC padding算法是有标准的,解密时根据标准可将padding字节去除。


Padding Oracle攻击简单来说就是攻击者利用密文解密后服务器判定padding是否正确这一提示(服务器将提示返回给客户端),通过paddingCBC加密标准的数学性质,能够以不可忽略的概率导出明文的部分信息甚至恢复出全部明文。对于对称加密,首先提出Padding Oracle攻击的是瑞士联邦理工大学Serge Vaudenay教授,他在2002年的EUROCRYPT上,发表了名为“Security Flaws Induced by CBC Padding Applications to SSL, IPSEC, WTLS...” [3] 的论文,文章中表明Padding Oracle的攻击思想在对称密码领域的可行性。从此揭开了CBC Padding Oracle攻击的序幕,从CBC模式下的Padding Oracle攻击称为Vaudenay攻击就可见一斑。


Vaudenay教授用“Bomb Oracle”CBC Padding Oracle做了一个形象的比喻,攻击者就像拆弹专家一样:攻击者首先精心伪造一串CBC数据块发给服务器,期望后者上当提供Oracle服务。服务器以为是正常TLS协议中来自客户端的CBC密文消息,处理时会做padding正确性检查。服务器若判断padding出错就好比拆弹失败,Bomb Oracle爆炸,当然谁也没被炸死,服务器返回padding error错误码;当Padding Oracle检查padding正确时不会返回padding error错误码,而是进一步检查HMAC,并以极大概率返回一个HMAC check error错误码;padding error错误码说明拆弹失败,HMAC check error错误码说明拆弹成功,攻击者根据两种错误码得出拆弹成功与否,拆弹失败后攻击者继续制作炸弹企图解密当前字节,成功拆弹一次攻击者就可以解密当前字节,以此类推攻击者可以再制作炸弹丢给服务器继续解密新的字节,直到解密全部数据。这样服务器返回的两种错误码起到了旁信道作用。


但在TLS中,我们知道拆弹成功与否的返回值是加密传送的,所以直接利用服务器发回的错误提示是不能让服务器充当Bomb Oracle攻击TLS的。然而由于每当拆弹成功后(即padding格式正确),服务器还要对数据完整性用HMAC算法做检查,由于攻击者对数据做了手脚,HMAC检查一般都会出错,服务器也会返回错误信息,让我们管后一种错误码叫做拆弹成功错误码。Brice Canvel Serge Vaudenay等人发现拆弹失败错误码与拆弹成功错误码在返回错误码的时间上有明显差别,当然差别是因为计算HMAC是需要额外时间的:若padding检查失败,拆弹失败好比服务器被炸毁就不会再做HMAC检查了,立刻就发回padding error错误码;如果padding检查通过,拆弹成功好比服务器还活着,就会继续检查HMAC,错误码就会晚一些时间发回。所以服务器对错误码加密也照样能让攻击者利用时间旁路信息来区分两种情况,timing side channel成立,Bomb Oracle仍然可以有效用于攻击TLS,只不过是旁信道是基于时间分析的,CanvelVaudenay等在CRYPTO 2003上发表了论文“Password interception in a SSL/TLS Channel”[4]报告了这一新进展。


随着上述攻击方式的公开,针对大部分TLS实现的Padding Oracle漏洞被修复。直到2013年,Lucky13攻击的出现才又将Padding Oracle适用于TLS的攻击重新带回人们视线,在工业界掀起了一阵风潮。由于我们分析的CVE-2016-2107漏洞,与Lucky13攻击密切相关,我们先来看看Lucky13攻击是如何又让Padding Oracle再次生效。


2 Lucky13再掀


2013年,Nadhem AlFardanKenneth PatersonSecurity & Privacy会议上发表了论文“Lucky Thirteen: Breaking the TLS and DTLS Record Protocols”[2],论文中指出了对TLSDTLS的一种Padding Oracle攻击方法。在timing-oracle之后引入TLS实现的MEEMAC Encode Encryption)算法,是把MAC放在加密里面的做法,MEEMAC只能对明文计算,所以对padding就不好做完整性保护。Lucky13中攻击者利用时间旁路信息,仍旧是服务器验证padding正确与否所用的时间,不同在于,这个时间差是极其微小的,是计算HMAC时由于padding长短差别造成的hash函数压缩次数不同的时间差!服务器在处理不同长度消息时进行HMAC计算过程中调用压缩函数的次数是不同的,也就是说,压缩函数的调用次数与HMAC消息长度有关,而HMAC消息长度值又与padding的长度有关,因此padding是否正确会直接导致压缩函数的调用次数不同,从而服务器处理消息的时间会不同, Timing Oracle再次生效。


3 CVE-2016-2107是个什么鬼?


针对Lucky13,AlFardanPaterson在论文第七节中提出了四种修改方案:

· 1. 将服务器返回错误码的答复时间随机化

· 2. 通过配置使用RC4流加密,无需padding

· 3. 使用 Authenticated Encryption,此乃正道

· 4. 精密设计constant time算法让服务器答复时间为恒定常数


其中第4种办法是最复杂的,AlFardanPaterson在论文第七节“Careful implementation of MEE-TLS-CBC decryption”小节中,明确了算法思路,并指出服务器响应时间选择constant time时要小心又小心。Lucky13攻击之后,constant time修正方案用了500多行的C代码,但Lucky13作者担心的事还是发生了,201653日公开的CVE-2016-2107漏洞就是AES-NI在论文constant time算法第3步实现不当引入的bug,HAMC位置不在最后一个block中时,代码居然忽略了整个HAMC的检查。很多人认为CVE-2016-2107是一个Timing Oracle Attack(甚至包括Redhat [7] Cloudflare [8] ),事实上不是这样[6],让我们分析如下。


首先,当AES-NI实现的算法第3步在最后CBC块中找不到HMAC时,攻击者想要oracle帮忙恢复的明文也不会在最后一块中,所以无论服务器按怎样长短的timing做答复时,攻击者都无法用padding oracle技术恢复最后CBC块中的明文消息。而企图在前面的CBC块(比如倒数第二块)中定位明文位置是非常困难的,就算能定位,padding格式也不会按不可忽略概率正确(回忆我们前面介绍的padding oracle工作原理:要利用padding oracle帮助恢复明文,padding格式必须正确)。


其次,这个AES-NI bug也并未向攻击者提供可利用的padding oracle服务。为说明这一点,我们可以对博客[6]展示的服务器明文答复错误消息做出如下分析。


TLS协议中服务器唯一会用明文答复错误消息的地点是Handshake协议中,让我们用下面两张TLS流程图予以解释。



图1 TLS RSA handshake and message exchange


TLS握手工作过程就如上图的所示,其中红色部分表示消息是加密的。首先客户端与服务端会互换hello messages,接着client发出一个ClientKeyExchange messsage,这个消息提示server:从现在开始直至(应用)会话结束让我们使用当前握手协议协商的会话密钥进行加解密和HMAC计算。的确,紧跟着Client会用新协商的会话密钥发出ChangeCipherSpec消息。服务器同样也会同意ChangeCipherSpec,并用新协商的会话密钥回应一个Server-Finished消息,从此之后,双方就可以互换加密过的应用数据消息了。如果攻击者用padding oracle技术修改了客户端发出的Client-Finished,会发生什么事呢?其实这正是博客[6]作者所做的攻击,服务器居然用明文返回了错误消息,感觉像是提供padding oracle服务了。现在让我们看看博客[6]中提到的用WireShark抓包获得的明文alert,是如何得到的呢。


有两点关于TLS的特性我们需要清楚:

· 1.加密Finished message的密钥与加密application message的密钥是相同的,但每一次会话会使用不同的密钥。

· 2.如果Finished message被攻击者攻击,服务器会回复明文的alert

2 TLS RSA handshake with an invalid Finished message


先解释为什么Server会用明文答复错误消息:如图2所示,攻击者如果攻击Client-Finished, 比如替换成一个无效的消息,Server解密,MAC padding检查就会出错,此时Server就认为没有和client成功协商密钥,算法等,于是就只好用明文回答 error allert了!这就是图34中抓包看见的两种明文错误消息:Bad Record MAC或者Record OverflowAlert MessageApplication传输阶段是加密的,这种情况下Handshake阶段出现的Alert Message明文暴露是唯一的例外[9],但这个alert只表明Client-Finished 是错误的,这个答复对攻击者并没有价值。





图3 Bad Record MAC





图4 Record Overflow



还需要指出的是,如果攻击者把别的会话中的application message CBC数据块放到Client-Finished位置,企图利用server发明文错误码充当padding oracle,应该是无效的,因为Handshake协议是让双方协商新的会话密钥,此处Server用于解密Client-Finished消息的会话密钥是本次Handshake协议新协商的,不会与以前用过的会话密钥相同,padding oracle不会提供正确解密。当Server发现并未成功协商新密钥时,会删除本次Handshake协议新协商的密钥,所以若攻击者在Handshake协议中发起重复攻击(padding oracle需要实施多次重复攻击),每次都会遇到新会话密钥问题,不会成功。


因此,我们认为通过WireShark抓包看到的明文错误码,并不能提供有效的oracle服务,正确debug后也还可以这样让服务器返回明文错误码。目前看来该漏洞很难被利用,至少在Handshake协议中未见可利用价值,但仍然是需要及时修复的,以防存在其它未知利用。


4们对四种修改方案分析

在解决Padding Oracle攻击问题时,我们还是要从Lucky13的四种解决方案出发。


第一种方式通过随机化服务器的答复时间,阻碍攻击者统计分析是针对Timing Attack一个自然的反应,但这样做效率性能上的损失无法与安全性平衡,因此不是一个好的办法;


第二种方式使用RC4流加密代替CBC-mode,然而它并不适用于DTLS。在TLS中使用流加密不会用到Padding,因此服务器无法被用作Padding OracleRC4广泛的支持TLS的实现,它可以有效的对抗BEAST攻击,在这一块也被广泛的应用。RC4流加密在MEE建设中有很好的理论支持。但是,CBC-mode转换到RC4会有几个潜在的缺点:首先,使用填充长度可变的CBC-mode允许少许的明文长度隐藏,使用流加密之后,这就不再可能了;第二,更重要的是,RC4 generator产生的密钥流的前若干个字节会有一些小的偏差,应对手段是丢掉比如前200个比特,但是TLS在没有丢弃这些就开始加密了;第三,RC4已经有多种攻击方式,安全性有所减低。与此同时,Google20159月宣布将于2016年禁用RC4[5]。因此使用RC4流加密也不是一个可行的选择。


第三种方式使用Authenticated Encryption,由于漏洞本质是因为对CBC Padding不提供任何数据完整性保证造成的,所以使用AES-GCM或者AES-CCM这样的Authenticated Encryption是解决的办法,从理论上讲,这样应该排除了所有基于MEE建设弱点的攻击,然而,我们不能排除实现时引入的潜在的侧信道攻击。进一步的问题是,目前,Authenticated Encryption只在TLS1.2中被添加了,TLS低于1.2的版本并没有支持,这是长期的选择目标;


第四种方式,即解密时用constant-time算法处理错误情况并返回错误信息,思路似乎最直接明了,然而在算法实现上却是意想不到的复杂,CVE-2016-2107攻击的发生恰恰以始料未及的形式印证了这一点!我们可以对实现constant-time算法的难度做出如下评估:算法输入含有随意长度的padding字节(在1-256字节范围中随意),这样的paddingHMACCBC加密中所处的位置“buffer underflow”到程序应该处理buffer位置(通常假定为CBC的最末块)negative offset方向很远的某个位置(考虑AES分组加密块长才16字节!)。我们还要格外注意到,该程序假定输入数据是来者不善的,对于这样的输入数据搞出constant-time算法是说来容易做到难啊!请注意,CVE-2016-2107漏洞的属性:恰恰是Lucky13作者建议的constant-time解密算法(文献[2]7节,约500C代码)第3步的实现中包含了错误:当代码探测到HMAC不在CBC最后数据块中时整个忽略了HMAC的检查,直接返回Record Overflow,形成了文献[6]所言之“UnluckyHMAC”! 因此在TLSOpenSSL的实现过程中,特别是用复杂冗长代码实现的算法中Bug很可能会接连不断的出现(即使在不断的Fix),也许这是一种无奈的现状选择。另外,constant-time解密算法的主要内容是对解密过程的所有情况一律加上255 bytes dummy padding check(因为最大的合法”padding内容是2560xFF),因此constant-time不仅易错,实际上也是耗费server(处于瓶颈位置)的宝贵CPU资源,长期来看不推荐使用。


四种修改方案小结如下:


5结合应用场景的修复建议



经过研讨,炼石网络CGLab认为,不能以一刀切的方式去处理,而是要结合不同的应用场景选择适合的方式来解决这个问题。我们结合企业的业务场景来分析,先判断您的业务系统是否必须依赖TLS1.1或以下。在一个开放式的应用环境中,有大量的客户端只支持TLS1.1或以下。场景1企业业务系统(包含所有客户端)可以仅支持TLS1.2及以上1.1 如果服务器支持重新编译,则建议参考社区最佳实践打补丁修复。具体的是:OpenSSL 1.0.2 users should upgrade to 1.0.2h,OpenSSL 1.0.1 users should upgrade to 1.0.1t 。[1]


1.2 如果服务器难以重新编译但支持配置,可以配置cipher suites为AES-GCM-mode。客户端必须选用Authenticated-Encryption-GCM,因为TLS server只会对客户端的选择就低不就高。场景2企业业务系统依赖TLS1.1及以下 2.1 如果服务器支持重新编译,则建议参考社区最佳实践打补丁修复。具体的是:OpenSSL 1.0.2 users should upgrade to 1.0.2h,OpenSSL 1.0.1 users should upgrade to 1.0.1t 。[1] 2.2 如果服务器难以通过重新编译升级,同时业务系统不得不使用TLS1.1及以下,则建议企业在防火墙这一层增加安全策略,例如使用SOC对TLS的大量失败连接进行统计,再手动或SOC自动联动IPS做出阻断。另外笔者经过咨询,某新锐安全公司的NGFW产品,支持用户自定义规则或策略,实现统计TLS的大量失败连接,并能触发规则进行阻断。从纵深防御的角度看,IPS或防火墙上的附加安全策略也能应对服务器的修复失效。




6对应用安全的进一步思考
对于OpenSSL这样一个被广泛使用的基础应用软件,我们相信社区及厂商已经建立了一套相对完善的安全开发机制,但仍然不定期会出现这样那样的漏洞,可见安全开发是一个多么大的挑战。进一步的,OpenSSL在部署后发现了安全漏洞该怎么应对?我们先参考一下GNU/Linux发行版中OpenSSL漏洞的两种典型做法:


· 1. 通常OpenSSL漏洞修复过程过于复杂,通常发行版社区会直接升级到新版本,比如FedoraUbuntu等。

· 2. 有大量老旧系统的企业客户的GNU/Linux厂商(SuSE, RedHat)在大部分情况下会做Backport fix,也即基于老版本的OpenSSL修复新漏洞、并且保证老版本修复后不产生新的问题。


以此类推,对于企业应用系统,理论上可以通过SDL(Security Development Lifecycle)把企业内建安全能力提高,提升应用系统的安全性,但就现状来看,还没有被很好的使用起来,到广泛被使用还有一定的距离。同样的,当企业应用系统部署后发现了安全漏洞怎么办?就像不能简单粗暴的要求企业不顾客户浏览器情况而把https服务都升级到只支持TLS 1.2,对于那些已部署到关键生产环境的、缺少内建安全能力的大量线上应用系统,不可能仅因为安全问题而推翻重新开发一遍,更何况大量应用都没有持续的开发支持了。我们认为Backport可以作为一种权宜之计,应能够在企业应用系统不改的情况下为其打安全补丁,为这些企业应用提供及时必要的更新升级。这也正是炼石网络CipherGateway云应用安全网关正在努力中的价值方向。


7引用

[1] https://www.openssl.org/news/secadv/20160503.txt

[2] http://www.isg.rhul.ac.uk/tls/TLStiming.pdf

[3] http://www.iacr.org/cryptodb/archive/2002/EUROCRYPT/2850/2850.pdf

[4] http://link.springer.com/chapter/10.1007/978-3-540-45146-4_34

[5] https://security.googleblog.com/2015/09/disabling-sslv3-and-rc4.html

[6] http://web-in-security.blogspot.hk/2016/05/curious-padding-oracle-in-openssl-cve.html

[7] https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-2107

[8] https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/

[9] http://www.rfc-base.org/txt/rfc-5246.txt


鸣谢:

感谢毛文波博士对本篇文章的思路指导和关键内容改进,感谢Joe对本篇文章的精心指导。感谢新锐安全公司上元信安郑曙光对NGFW规则支持情况的反馈,也感谢HardenedLinux社区Shawn的反馈意见。