Padding Oracle Attack学习笔记
前言
周末的校赛出了这题,最近一直对数学性强的加密研究较多,对于此类算法性强的加密方法没有过多关注,结果比赛就是被socket
的通信坑了大半天v_v
这篇文章主要是简单记录一下,具体原理和攻击方法有很多师傅讲的要比我好很多。
而且写完我感觉也挺乱的,似乎只有脚本可以供各位参考
AEC-CBC加密
加解密基本原理图:
CBC
加密时按AES.block_size
字节分块将明文分块,每块异或分别使用key
加密,加密后输出同时自身参与下一块的异或操作。解密时每一块密文通过key
作用再与前一块密文进行异或得到明文。
注意无论是加密还是解密,都与且仅与上一块通过单次异或作用。
PKCS7 Padding
注意到上述CBC
加解密过程中将明文密文按AES.block_size
字节分块,如果明文长度不是AES.block_size
字节的整数倍呢?需要使用PKCS7 Padding
的数据填充规则,以AES.block_size = 16
为例,下面演示padding
的过程。
无论明文多长,最后一块的长度一定是\(\{1,2,3,\cdots,14,15,16\}\),对每种情况的最后一块数据进行填充(包括最后一节为16字节的情况),补充的字节数是 到下一个16字节倍数所需字节数,每个填充字节的值也是到下一个16字节倍数所需字节数。
听起来很拗口,下面看具体情况:
最后一节为\(15\)个字节,需要补充\(1\)个字节达到\(16\)的倍数,则填充\(1\)个0x01
最后一节为\(10\)个字节,需要补充\(6\)个字节达到\(16\)的倍数,则填充\(6\)个0x06
最后一节为\(2\)个字节,需要补充\(14\)个字节达到\(16\)的倍数,则填充\(14\)个0x0e
最后一节为\(16\)个字节,需要补充\(16\)个字节达到\(16\)的倍数,则填充\(16\)个0x10
因此,补充后最后一节的可能性有如下16种情况:
1 | ... | XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX 01 |
下面这种具体情况是正确的:
1 | 35 70 f2 45 09 d3 a3 6b 90 3e 3a 58 03 03 03 03 |
下面这种具体情况是错误的:
1 | 35 70 f2 45 09 d3 a3 6b 90 3e 3a 58 07 02 03 03 |
正确的情况在Unpadding
中可以正确还原出明文
错误的情况在Unpadding
中会出错
如果恰巧,当服务端把是否Unpadding
成功的信息泄露出来,就可以针对其进行破解
例题
1 | from base64 import * |
首先进工作量证明,通过后得到明文加密后的(base64)信息,然后用户即可发送数据让服务端进行验证。
攻击流程
攻击流程也可以大致写出:
- 保存真正明文加密后的密文,其中前16字节为
IV
初始化向量 - 创建一个\(32\)字节的数组,用于实时更新将要攻击的数据列表,前\(16\)字节位初始化为先前得到的
IV
向量;创建一个\(16\)字节的数组,用于寄存中间值。 - 对攻击列表的最后一位从
0x00
到0x01
遍历,直到服务端的Unpadding
成功,且当改变倒数第二位时,Unpadding
过程仍然通过,证明此轮Unpadding
的结果末位确实为0x01
- 把攻击列表的末位与
0x01
异或得到的结果即为此轮解密后的中间值 - 把攻击列表的末位修改为中间值 异或
0x02
以实施对倒数第二位的攻击 - 从第三步重复,对倒数第二位实施攻击,直到\(16\)个字节均攻击完毕
- 改攻击列表前\(16\)字节为密文第一组,从第三步重复,直到每部分密文攻击完毕
攻击参考脚本
1 | from base64 import * |
结语
我真的感觉文章写完后超级超级乱,就留着自用吧(逃
参考学习
- 非常清晰的动画讲解↓ Padding Oracle 攻击 - BiliBili
__END__