为什么说是再解读呢?目前关于Padding Oracle攻击的介绍,比较好的文章包括的内容,都取自于这篇外文。但是,该文在论述一个关键问题,即如何确认Padding位数时,并没有提及,这让许多较真的读者会有很大的疑惑。本人亦如此。因此,我想再把思路做个梳理。

1.分组密码和填充

常用的对称加密算法,如DES和AES,在用密钥加密数据时,只能加密和密钥长度相同的数据。对于超长数据,我们需要将其切分成块。这就带来一个问题,可能最后一个块,无法和密钥“对齐”(当然,这也包括原始数据本来就比密钥短的情况)。这就需要一些数据去填充最后的几位。常用的填充算法即PKCS#5,在数据填充中,使用缺失的位数长度来统一填充,说起来麻烦,上图即可明白:

即缺5位,就用0×05填充;缺2位,就用0×02填充;如果刚刚好,还要扩展出一个块,全用0×08填充。

2.初始向量和CBC加解密过程

如果每一个块都用同一个密钥加密,很容易使用统计学原理去分析和破解密文(原理大致如同e字母在英文单词中出现的概率是非常高的,因此通过统计分析,大致可能猜出X代表了e),为此CBC加密过程引入了一个初始向量,使得每一个块的加密密钥,都包涵有上一个块的密文的反馈,从而解决了统计学攻击问题。还是上图比较容易理解,因为仅仅涉及到一个异或运算,所以不做解释,其中的Encryption/Decryption,就是加密算法所在。但是,Padding Oracle攻击,恰恰是避过了这一块的实现细节,因此大家可以忽律那个框框,如图:

而解谜,就是一个反过程

因此,双方除了要交换密文外,还需要交换初始向量

3.Padding Oracle的攻击条件

并不是使用CBC的服务都有弱点.我们可以构想如下一个可以被利用的漏洞服务器,来解释其特点:对于请求,会有如下反馈:

1. 如果解密过程没有问题,明文验证(如用户名密码验证)也通过,则会返回正常 HTTP 200

2. 如果解密过程没有问题,但是明文验证出错(如用户名密码验证),则还是会返回 HTTP 200,只是内容上是提示用户用户名密码错误

3. 如果解密过程出问题了,比如Padding规则核对不上,则会爆出 HTTP 500错误。

这样举例,仅仅是为了说明,可被利用的服务器的特点是:对于解密过程自身的异常,会有一个特殊的错误提示,有别于明文验证出错。

4.Padding Oracle攻击过程

该例子还是沿用这篇外文中的例子。

假设一个服务的请求如下: ?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6,注意其前8字节7B216A634951170F是初始化向量。

我们来看看这样一个服务,是如何加解密一个字符串BARIN;12;1的(加密本身用了3DES,但这不是问题的重点,可以忽略)。

解密过程如下

注意:最终的Padding是符合验证的。

通过解密过程我们可以看出,因为初始化向量是可以知道的,如果我们知道中间值,即Intermediary Value,在不需要知道加密过程时,通过简单的异或,就可以知道明文是什么了。甚至,我们还可以通过中间值仿造任意的明文字段做暴力攻击。

现在假设有一个中间人,截获了报文,那么它可以这样操作:首先,向服务器发送请求时,把初始化向量全部设为0×00,且只保留第一个块,最终报文是?UID=0000000000000000F851D6CC68FC9537。其解密过程如下:

因为最终填充校验有误,自然服务器会报错HTTP 500。

之后,中间人将初始向量递增1,用?UID=0000000000000001F851D6CC68FC9537去试探,自然也是报错