一、漏洞背景
10月14号由Google发现的POODLE漏洞(Padding Oracle On Downloaded Legacy Encryption vulnerability),可被攻击者用来窃取采用SSL3.0版加密通信过程中的内容,又被称为“贵宾犬攻击”。虽然该攻击利用有一定的难度,需要完全控制网络流量,但在公共wifi遍地都是和强调国家之间对抗的APT背景下,该漏洞仍有不小的影响,我们的小伙伴也紧急分析了漏洞原理,poc仍在验证中,稍后放出。
二、SSLv3.0协议基础
协议协商数据
在协议握手阶段,协商的数据包括:
明文/密文分组长度:长度一般为16字节。
初始化向量IV:根据SSLv3.0协议定义的算法生成,要求随机性较高,与明文/密文分组长度相同(16字节)。
对称密钥Key:即SSLv3.0协议中定义的主密钥(the Master Secret),用于数据加密。
加密模式:常见的加密模式有多种,本漏洞本质就是SSLv3.0协议推荐的CBC加密模式可能泄露信息。
数据填充与分组
明文加密之前和密文解密之前需要分组,每个分组长度为128比特,即16字节。
对于待加密的明文数据,分组处理过程为:
(1)计算明文签名MAC(Message Authentication Code,消息验证码)序列,长度为20字节。
(2)将MAC序列附在明文数据之后组成平文(Plaintext),将Plaintext的长度填充至16字节的整数倍。
填充方式为:如果原始Plaintext长度不是16字节的整数倍,再其后附加零个、一个或多个Padding字节,再附加1个字节,其值为Padding长度;如果原始Plaintext长度正好是16字节的整数倍,则在其后附加15字节长度的Padding序列,再附加1个Padding长度,其值为15。
(3)将填充后Plaintext每16字节分为一组,称为平文块(Plaintext Block),使用符号P1 , P2 … Pn 表示。
初始化向量IV用于首次加密,此时使用P0表示。
对于待解密的密文数据,由于数据长度肯定为16字节的整数倍,所以其直接按照16字节长度分组,每个分组称为密文块(Cipher Block),使用符号C1 , C2 … Cn表示。
初始化向量IV用于首次解密,此时使用C0表示。
CBC模式原理
在CBC模式中,每个平文块(Plaintext Block,即明文分组块)先与前一个密文块(Cipher Block)进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有平文块。同时,为了保证每条消息的唯一性,在加解密过程初期需要使用初始化向量IV。
基于CBC加密模式的对称加密流程如下图:
即,对于每一个平文块Pi,得到密文块Ci:
换个角度考虑,平文中的微小改变会导致其后的全部密文块发生改变。
基于CBC加密模式的对称加密流程如下图:
即,对于每一个密文块Ci,得到平文块Pi:
因此,如果密文块Ci被修改,不会影响对密文块Ci-1的解密结果,而Ci及Ci之后的解密结果Pi’,Pi+1’ … Pn’ 将与原始的Pi,Pi+1 … Pn不同。
从密文得到平文后,服务端会立即验证明文的MAC以确保数据有效性,根据前述的平文填充方式,SSLv3.0协议定义的验证原理为:
(1)根据平文数据最后一个字节的得到Padding序列长度,移除该字节以及Padding序列后,平文的最后20字节数据是客户端计算得到的MAC序列。
(2)移除该MAC序列得到的数据是明文数据,服务端重新计算该段数据的MAC序列并与客户端MAC序列对比,即可确定数据是否有效。
三、POODLE漏洞分析
根据之前所述,如果明文数据的长度加20字节的MAC序列长度正好为16字节的整数倍,平文Padding算法会在Plaintext的最后附加15字节的Padding序列和1字节的Padding序列长度(值15),即最终的平文的最后16字节属于附加部分,加密后对应密文分组的最后一个密文块Cn。该在这种情况下,如果使用密文中的某一个密文块Ci替换密文块Cn并发送给服务端,服务端有可能认为数据是有效的,满足这种可能性必须要求解密后的数据最后一个字节值是15,这样恰好既不影响原始明文序列,也不影响MAC序列,从而通过服务端对MAC序列的验证。
定义密钥为k的对称加密算法的加密过程和解密过程分别为Dk( )和Ek( )。
此时:
Pn’= Dk(Cn’)⊕Cn-1 = Dk(Ci)⊕Cn-1
且
Pn’[15] = 15
即:
Dk(Ci)[15]⊕Cn-1 [15]= 15
由于:
Pi[15] = Dk(Ci)[15]⊕Ci-1[15]
所以:
Pi[15] = 15⊕Cn-1 [15]⊕Ci-1[15]
很明显,此时密文块Ci对应的平文块Pi的最后一个字节可以通过计算得到。
四、POODLE漏洞利用
到此,在前述假定的条件下仅仅解密一个字节的数据并无任何实际意义,然而,Google安全研究员在其发布的分析报告This POODLE Bites: Exploiting The SSL 3.0 Fallback 中考虑了这样一个针对HTTPS协议的攻击场景:
(1)攻击者可以实施中间人攻击,控制用户流量以及控制客户端发送AJAX请求;
(2)攻击者的目标是获取用户的cookies;
(3)攻击者已经知道cookies数据长度。
对于(3)条假设并不一定完全成立,这里首先假定在其成立的条件下考虑POODLE漏洞的利用方式。
假设请求明文的Plaintext如下:
POST /path Cookie:…\r\n\r\nbody ‖ 20bytes-MAC ‖ 15-bytes-padding || 15
攻击者可以控制path和body的长度使上述Plaintext的长度为16字节的整数倍,并且,由于已知cookies的长度,控制欲解密的cookies字节位于某个平文块Pi的最后一个字节上。
首先,设置客户端请求使P5[15] = ‘e’,请求加密前的Plaintext为:
图 计算第一个数据
中间人截获密文Ciphertext之后使用C5代替C11后传递请求,如果发现服务端解密后验证失败,控制客户端变换请求的path内容再发送,一般经过不超过256次变换,可能会有一次使服务器解密后验证成功,即中间人可以根据上面介绍过的方式计算得出该处明文字节数据。
然后,控制客户端请求的path长度和body长度,比如path长度加1同时body长度减1:
图 计算第二个数据
继续发送请求、中间人拦截替换再发送等操作,依次可以分析出整个cookies数据。
在cookies长度不确定的情况下,可以通过控制增加客户端的path长度并对比密文Ciphertext长度,基本在16个请求以内就可以确定其实际长度。比如:
第一次请求的Plaintext为:
GET /\r\nCookie: n1=v1\r\n\r\n || 20bytes-MAC ‖ padding
即:
图 计算cookies长度的第一次Plaintext
此时,Ciphertext的总长度为48字节。
第二次请求的Plaintext为:
GET /A\r\nCookie: n1=v1\r\n\r\n || 20bytes-MAC ‖ padding
图 计算cookies长度的第二次Plaintext
此时,Ciphertext的总长度为48字节。
第三次请求的Plaintext为:
GET /AA\r\nCookie: n1=v1\r\n\r\n || 20bytes-MAC ‖ padding
图 计算cookies长度的第三次Plaintext
此时,Ciphertext的总长度为48字节。
第四次请求的Plaintext为:
GET /AAA\r\nCookie: n1=v1\r\n\r\n || 20bytes-MAC ‖ padding
图 计算cookies长度的第四次Plaintext
此时,Ciphertext的总长度为48字节。
第五次请求的Plaintext为:
GET /AAAA\r\nCookie: n1=v1\r\n\r\n || 20bytes-MAC ‖ padding
图 计算cookies长度的第五次Plaintext
此时,Ciphertext的总长度为64字节,从而知道第一次的Ciphertext的总Padding长度为4字节(3字节Padding序列和1字节的Padding序列长度),而Ciphertext总长度为48字节,“GET /\r\n”序列长度7字节,MAC序列长度为20字节,所以“Cookie: n=v\r\n\r\n”长度为15字节。
参考:
[1] RFC6101: http://tools.ietf.org/html/rfc6101
[2] Google分析报告:https://www.openssl.org/~bodo/ssl-poodle.pdf
[3] 块密码的工作模式:
http://zh.wikipedia.org/wiki/%E5%9D%97%E5%AF%86%E7%A0%81%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F