Padding Oracle Attack学习笔记

Padding Oracle Attack学习笔记

前言

最近看到Padding Oracle Attack,是对加密算法的CBC模式的破解,很是好奇,找了些资料,动手实现了破解算法。 但是过程有点点曲折,记录下心得体会。

原理

以DES的CBC模式为例,分组加密算法在加解密时,都需要把消息分组,一般为8或16字节。以解密为例:
分组解密

理解破解算法的几个关键点:

关键点1:padding bytes

padding bytes,即明文不足分组长度时,进行填充的字节。以8字节分组,PKCS5模式为例,当明文为HELLO时,不满8个字节,剩余3个字节的填充字节为0x03,即:

padding byte = padding length = block size - block input length
//填充字节 等于 填充长度 等于 分组长度 - 分组输入长度

因此,填充字节只能是0x01, 0x02…0x08。 0x08表示输入长度为8的倍数字节时,后面也会有8个字节的填充数组。 也就是说,填充字节肯定存在,且范围是1~8。
(其他分组长度类似原理)

关键点2:padding error

当构造的输入错误时,会产生padding error,如java中是BadPaddingException,其他语言可自行尝试。 这点很关键,因为Padding Oracle Attack的核心就是这个,利用padding error来不断进行输入尝试。 编写破解工具时,可能看不到异常,但是一定要能根据返回信息判断是不是产生了padding error,如果不能确定,破解是进行不下去的。

关键点3:算法

与解密示意图对应,我们将分组密文进行 block ciper decryption后得到的字节数组称为Intermdiate bytes,将与Intermediate bytes进行XOR的字节数组称为IV,分组密文用block表示,block[i]表示第i个分组密文, plain block[i]表示第i个分组明文,intermediate[i]表示第i个分组密文的Intermdiate bytes。

ok,让我们捋一捋流程:

  1. block[i] decrypt得到 Intermediate bytes, 这个操作跟key(密钥)有关,每个密文分组得到的Intermediate bytes是固定的

  2. Intetermedaite bytes 异或 IV 得到明文。注意图中的解密过程,前面分组的密文会与后面一个分组的解密密文异或,最终得到后面一个分组的明文。即对应的block[i]的IV为block[i-1]。因此,解密一定从最后一个分组开始。

  3. 从最后一个分组开始,用全0数组pseudo block[i-1]代替真实的block[i-1], 通过不断的调整psdudo block[i-][7](最后一个字节),通过判断是否返回padding error来确定填充字节是否正确,即0x01,如果正确,则意味着可以得到明文:

     if intermediate[i][7] XOR pseudo block[i-1][7] == 0x01:
     	//得到intermedaite bytes
     	intermediate[i][7] = pseudo block[i-1][7] XOR 0x01
     	//从而得到分组明文
     	plain block[i][7] = intermediate[i][7] XOR block[i-1][7]
    

    因为一个字节的范围是从0~255,所以对于一个字节的尝试最多是256次,

  4. 如果构造数组得到正确的填充字节0x01,则意味着intermediate[i]的最后一个字节确定了,从而可以继续调整,当填充字节为0x02时:

     pseudo block[i-1][7] = intermediate[i][7] XOR 0x02
    

    调整pseudo block[i-1][6]的字节值,可以得到block[i][6]的明文字节;以此类推,block[i]就可以全部解密。

  5. 重复步骤3、4,即可以得到全部分组的明文。

遇到的坑

看完上面的原理,像我这种弱鸡会觉得,“靠,这么简单,我要试一试”。 事实会再次证明你too young。。。

坑1

算法的第3点,为毛要用全0数组充当伪造的数组,而且要从最后一个字节开始尝试,且得到的填充字节就一定是0x01?

抱歉,我也没有确定的答案,我找到的源码和资料都是直接这么搞的,更狠的是原作者的PPT上说的是random bytes(希望是我英语不好,读的不仔细吧)。 但是我有个推测:block[i]密文decrypt操作得到的intermediate[i],字节重复且在0~8之前的概率非常之小。

因此,当从全0数组的最后一个字节开始尝试时,遇到非padding error的情况,就极大概率对应填充字节为0x01。 因为,假设此时正确填充字节为0x03,则意味着block[i]的5、6、7这3个字节对应的intermediate都是0x03。

当然,我觉得就算出现此类极端情况,也是有补救措施的。 比如对于填充字节0x01得出一个错误的pseudo block[i][7],那很可能对于0x02,得不出正确的pseudo block[i][6],这个时候退回去,跳过当前的pseudo block[i][7]值往后尝试;以此类推,也可以推导出正确的结果。

当然这个是推测,需要翻算法和源码验证。

坑2

算法第5点,看似正确,转念一想,对于第一个密文分组,咱是不知道原始IV的啊,怎么破?

抱歉,这个真的无解。。。翻的资料都说“初始IV不重要,一般放在第一个分组,明文传输”。。。

刚开始看算法的时候,纠结了很久,因为推不出第一个分组的明文,才一直觉得自己是没有透彻理解原理,就是因为没有注意到这句话。。。

总结

看安全的材料,感觉搞安全的同学们还是挺NB的,佩服。。。不过,惯例,槽还是要吐的,上面那两个坑,尤其第一个,搜到的材料都没有解释,看来大家都比较忙。。。

附录:

  1. 《白帽子讲WEB安全》
  2. 破解算法PPT
  3. PadBauster源码地址
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章