CBC(Cipher Block Chaining)即密码分组链接,是一种加密模式。在CBC模式中,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
由流程图可以看出解密就是加密的逆过程,但有几点图中没有提到:
PKCS #5 与 PKCS #7 的唯一不同就是前者只适用于8字节以内的填充,而后者填充范围包括 0x00~0xff
以 PKCS #5 为例,将明文填充到 8 字节的整数倍,如果明文已经满足 8 字节的整数倍,那就在明文的最后再添加 8 字节的填充,而填充的内容取决于需要填充的长度,如果需要填充 7 个字节,那就要填充 7 个 0x07
,如果明文已经满足 8 字节的整数倍,那就在明文的最后再填充 8 个 0x08
DES算法进行加密时的填充规则是 PKCS #5、填充最多 8 位,而AES算法进行加密时的填充规则是 PKCS #7、填充最多 16 位。
Padding 意为填充,Oracle 在此意为提示,在对密文进行解密的过程中,如果解密得到的结果末尾不符合填充规则,那通常相应的解密库会抛出一个异常,提示填充不正确。简单来说,Padding Oracle 就是提示数据不符合填充规则的意思。
Padding Oracle Attack,顾名思义,就是根据返回给我们填充数据是否符合规则的提示进行攻击的方式,此种攻击方式有几个前提条件
已知服务端可以根据检测填充是否正确来为我们返回不同的值,即可以实现 Padding Oracle,那么我们就可以根据其不同的返回值不断构造初始向量 IV 来爆破中间值(Intermediary Value),例如
813EC9D944A5C8347A7CA69AA34D8DC0
9F0B13944841A832B2421B9EAF6D9836
由于填充是在每个明文的末尾位置,所以我们构造 IV 需要从结尾开始,当填充为 0x01
时,按照填充规则,只填充末尾最后一位,此时如果服务器返回解密正确,则明文的形式应该为 ******************************01
,那么我们从 0x00~0xff 爆破最后一位的 IV,得到当最后一位为 0x17
时解密正确,即
Padding: 0x01
iv: 00000000000000000000000000000017
plain: ******************************01
此时我们利用填充位 xor 构造的 IV 对应位,即可得到正确的中间值,因为在密文不变的情况下,解密得到的中间值是始终不变的
Padding: 0x01
iv: 00000000000000000000000000000017
IValue: 00000000000000000000000000000016
plain: ******************************01
经过第一轮的爆破,我们已知了中间值的最后一位,那当我们开始第二轮爆破时,就可以预先通过已知的中间值与本轮的填充计算出 IV 的已知位
Padding: 0x02
iv: 00000000000000000000000000000014
IValue: 00000000000000000000000000000016
plain: ******************************02
再通过爆破倒数第二位的 IV,计算出倒数第二位的中间值
Padding: 0x02
iv: 0000000000000000000000000000f414
IValue: 0000000000000000000000000000f616
plain: ****************************0202
依次类推,我们就可以爆破出完整的中间值
Padding: 0x10
iv: d67a7aa57808d75782356efa9f1ce606
Ivalue: c66a6ab56818c74792257eea8f0cf616
plain: 10101010101010101010101010101010
注:上述 plain 不是密文正确解密得到的明文,只是我们通过构造让服务器认为解密正确得到的明文
当我们得到一整个完整的中间值时,根据 CBC模式 的解密流程,我们将中间值 xor IV 即可得到正确的明文
IValue: c66a6ab56818c74792257eea8f0cf616
IV: 9F0B13944841A832B2421B9EAF6D9836
plain: 5961792120596F752067657420616E20
text: "Yay! You get an "
爆破 IValue 部分
for l in range(length / 2): # 爆破每一位 Ivalue (0~15),总长度依次叠加
iv = ''
padding = l + 1 # 1~16
for ll in range(l): # 根据已知 Ivalue 修改 iv
iv += hex(ord(Ivalue.decode('hex')[ll]) ^ padding)[2:].zfill(2)
for iv_test in range(256):
iv = iv[0 : l * 2]
iv += hex(iv_test)[2:].zfill(2)
#print iv
iv = iv.ljust(length, '0')
#print iv
data = iv.decode('hex')[::-1].encode('hex') + Cry[flag]
ctext = [(int(data[i:i+2],16)) for i in range(0, len(data), 2)]
rc = Oracle_Send(ctext, 2)
if str(rc) == '1': # padding 正确。根据 padding 值和此时 iv 计算 对应位置 Ivalue
Ivalue += hex(padding ^ iv_test)[2:].zfill(2)
print "Ivalue: ", Ivalue.ljust(length, '0').decode('hex')[::-1].encode('hex')
break
print "iv: ", iv.decode('hex')[::-1].encode('hex')
print '-' * 50
由于实际解密时填充从末尾开始,我们为了方便字符串操作选择先正向叠加,在和需要解密的密文拼接在一起之前再逆序(题目背景是给服务器上传一段16进制字符串密文,服务器会将前一半密文当做后一半密文解密的IV,当服务端返回值为 '1'
时,意为解密正确,即明文填充无误)
完整代码
# coding=utf-8
from oracle import *
c = '9F0B13944841A832B2421B9EAF6D9836813EC9D944A5C8347A7CA69AA34D8DC0DF70E343C4000A2AE35874CE75E64C31'
block_num = 3
length = len(c) / block_num
Cry = []
for i in range(block_num):
Cry.append(c[i * length : (i + 1) * length])
#print Cry[0], Cry[1], Cry[2]
Oracle_Connect()
# iv = ‘9F0B13944841A832B2421B9EAF6D9836’
# cry1 = '813EC9D944A5C8347A7CA69AA34D8DC0'
# cry2 = 'DF70E343C4000A2AE35874CE75E64C31'
mess = ''
flag = 1
for i in range(1, block_num):
IV = Cry[i - 1].decode('hex')
Ivalue = ''
for l in range(length / 2): # 爆破每一位 Ivalue (0~15),总长度依次叠加
iv = ''
padding = l + 1 # 1~16
for ll in range(l): # 根据已知 Ivalue 修改 iv
iv += hex(ord(Ivalue.decode('hex')[ll]) ^ padding)[2:].zfill(2)
for iv_test in range(256):
iv = iv[0 : l * 2]
iv += hex(iv_test)[2:].zfill(2)
#print iv
iv = iv.ljust(length, '0')
#print iv
data = iv.decode('hex')[::-1].encode('hex') + Cry[flag]
ctext = [(int(data[i:i+2],16)) for i in range(0, len(data), 2)]
rc = Oracle_Send(ctext, 2)
if str(rc) == '1': # padding 正确。根据 padding 值和此时 iv 计算 对应位置 Ivalue
Ivalue += hex(padding ^ iv_test)[2:].zfill(2)
print "Ivalue: ", Ivalue.ljust(length, '0').decode('hex')[::-1].encode('hex')
break
print "iv: ", iv.decode('hex')[::-1].encode('hex')
print '-' * 50
Ivalue = Ivalue.decode('hex')[::-1]
mess += "".join(chr(ord(x) ^ ord(y)) for x, y in zip(Ivalue, IV))
print '=' * 70, '\n', mess, '\n', '=' * 70
flag += 1
Oracle_Disconnect()
print mess
完整输出
Connected to server successfully.
Ivalue: 00000000000000000000000000000016
iv: 00000000000000000000000000000017
--------------------------------------------------
Ivalue: 0000000000000000000000000000f616
iv: 0000000000000000000000000000f414
--------------------------------------------------
Ivalue: 000000000000000000000000000cf616
iv: 000000000000000000000000000ff515
--------------------------------------------------
Ivalue: 0000000000000000000000008f0cf616
iv: 0000000000000000000000008b08f212
--------------------------------------------------
Ivalue: 0000000000000000000000ea8f0cf616
iv: 0000000000000000000000ef8a09f313
--------------------------------------------------
Ivalue: 000000000000000000007eea8f0cf616
iv: 0000000000000000000078ec890af010
--------------------------------------------------
Ivalue: 000000000000000000257eea8f0cf616
iv: 0000000000000000002279ed880bf111
--------------------------------------------------
Ivalue: 000000000000000092257eea8f0cf616
iv: 00000000000000009a2d76e28704fe1e
--------------------------------------------------
Ivalue: 000000000000004792257eea8f0cf616
iv: 000000000000004e9b2c77e38605ff1f
--------------------------------------------------
Ivalue: 000000000000c74792257eea8f0cf616
iv: 000000000000cd4d982f74e08506fc1c
--------------------------------------------------
Ivalue: 000000000018c74792257eea8f0cf616
iv: 000000000013cc4c992e75e18407fd1d
--------------------------------------------------
Ivalue: 000000006818c74792257eea8f0cf616
iv: 000000006414cb4b9e2972e68300fa1a
--------------------------------------------------
Ivalue: 000000b56818c74792257eea8f0cf616
iv: 000000b86515ca4a9f2873e78201fb1b
--------------------------------------------------
Ivalue: 00006ab56818c74792257eea8f0cf616
iv: 000064bb6616c9499c2b70e48102f818
--------------------------------------------------
Ivalue: 006a6ab56818c74792257eea8f0cf616
iv: 006565ba6717c8489d2a71e58003f919
--------------------------------------------------
Ivalue: c66a6ab56818c74792257eea8f0cf616
iv: d67a7aa57808d75782356efa9f1ce606
--------------------------------------------------
======================================================================
Yay! You get an
======================================================================
Ivalue: 000000000000000000000000000000cb
iv: 000000000000000000000000000000ca
--------------------------------------------------
Ivalue: 000000000000000000000000000086cb
iv: 000000000000000000000000000084c9
--------------------------------------------------
Ivalue: 000000000000000000000000004686cb
iv: 000000000000000000000000004585c8
--------------------------------------------------
Ivalue: 000000000000000000000000a84686cb
iv: 000000000000000000000000ac4282cf
--------------------------------------------------
Ivalue: 000000000000000000000091a84686cb
iv: 000000000000000000000094ad4383ce
--------------------------------------------------
Ivalue: 00000000000000000000ad91a84686cb
iv: 00000000000000000000ab97ae4080cd
--------------------------------------------------
Ivalue: 00000000000000000077ad91a84686cb
iv: 00000000000000000070aa96af4181cc
--------------------------------------------------
Ivalue: 00000000000000007177ad91a84686cb
iv: 0000000000000000797fa599a04e8ec3
--------------------------------------------------
Ivalue: 000000000000003f7177ad91a84686cb
iv: 0000000000000036787ea498a14f8fc2
--------------------------------------------------
Ivalue: 000000000000c33f7177ad91a84686cb
iv: 000000000000c9357b7da79ba24c8cc1
--------------------------------------------------
Ivalue: 0000000000aec33f7177ad91a84686cb
iv: 0000000000a5c8347a7ca69aa34d8dc0
--------------------------------------------------
Ivalue: 000000006daec33f7177ad91a84686cb
iv: 0000000061a2cf337d7ba19da44a8ac7
--------------------------------------------------
Ivalue: 000000e46daec33f7177ad91a84686cb
iv: 000000e960a3ce327c7aa09ca54b8bc6
--------------------------------------------------
Ivalue: 0000e9e46daec33f7177ad91a84686cb
iv: 0000e7ea63a0cd317f79a39fa64888c5
--------------------------------------------------
Ivalue: 0010e9e46daec33f7177ad91a84686cb
iv: 001fe6eb62a1cc307e78a29ea74989c4
--------------------------------------------------
Ivalue: c010e9e46daec33f7177ad91a84686cb
iv: d000f9f47dbed32f6167bd81b85696db
--------------------------------------------------
======================================================================
Yay! You get an A. =)
======================================================================
Connection closed successfully.
Yay! You get an A. =)