S

SkYe231

V1

2022/11/21阅读:16主题:极客黑

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 表示

加密

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

解密

  1. 首先从最终的密文中提取出IV (IV为加密时指定的X位) //如果加密时没有加入IV则不用提取
  2. 将密文分组
  3. 使用密钥对第一组密文A解密得到 middle_A,然后用 IV 进行异或得到第一组明文
  4. 使用密钥对第二组密文解密得到 middle_B,然后用Cipher_A与middle_B进行异或得到第二组明文
  5. 重复3-4 直到最后一组密文

Padding Oracle Attack

需要注意的是,Padding Oracle Attack 攻击与具体的加密算法无关。

攻击条件

  1. 攻击者能够获得密文(Ciphertext),以及附带在密文前面的IV(初始化向量)
  2. 攻击者能够触发密文的解密过程,且能够知道密文解密是否成功
  3. 解密过程中 IV 可控

Padding

在前文有提及,如果明文的长度不是16字节的整数倍,需要对最后一个分组进行填充(padding),CBC的填充规则有PKCS5和PKCS7的区别,这里使用的是PKCS7 ,即缺少N字节,就用 N 个 \xN 填充,如缺少7位则用 7 个 \x07 填充,因此,正确的填充格式有:

0x01
0x02 0x02
0x03 0x03 0x03
....

Attack 思路

  1. 每次发送一个分组,则解密时都会用到IV

  2. 爆破分组最后一个字节:

    • 根据 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]

  3. 爆破分组倒数第二个字节

    • 构造 New_IV[-1] ^ Intermediary_Value [-1] = 0x02

      上一步已经得到了Intermediary_Value [-1] ,则

      New_IV[-1]  = Intermediary_Value [-1] ^ 0x02 
    • 根据 New_IV[-2] ^ Intermediary_Value [-2] = 0x02 爆破

      与爆破最后一个字节的思路相同

  4. 分组其他字节依此类推

巅峰极客2020 babyweb

题目逻辑梳理

  1. 登陆失败也会返回一个 Set-Cookie,其中有一个字段为 admin_password
  2. 当带着cookie访问login,会解密cookie中的 admin_password 字段,解密失败会报错 padding error.
  3. 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

分类:

前端

标签:

计算机网络

作者介绍

S
SkYe231
V1