padding oracle attack

写在前面

是pico上的一个题目,一般的padding oracle是破解密文,pico上的这个是利用padding oracle在IV可控的情况下构造任意明文的对应密文

Padding Oracle

网上相关的文章特别多,有一个我觉得介绍的特别好的,顺便还提到了cbc翻转攻击。padding oracle

CBC Encryption

enc

CBC Decryption

dec

padding pcks7

如果按照16字节一块,那么最后一块不满足16字节的时候,假设差6块刚好填满16字节,那么padding就是6*'\x06',而padding oracle就是发给他一密文,oracle判断这个密文是否合法。如果解密出来的padding有误,那么会告诉你padding error.

构造任意密文

现在任意拿一块密文,利用padding oracle可以得到另一个密文,(因为就两块就把这个得到的叫做iv)和这个密文解密出来的padding刚好是16*'\x10',假设我需要的密文的最后一块需要解密出来要为:

1
success\x09\x09\x09\x09\x09\x09\x09\x09\x09

那么根据iv ^ middle=16*'\x10',iv' ^ middle = 'success\x09\x09\x09\x09\x09\x09\x09\x09\x09'
可以得到我们构造出的新的iv’应该要为:

1
iv' = "success\x09\x09\x09\x09\x09\x09\x09\x09\x09" ^ 16*"\x10" ^ iv

但是我们需要进一步改造解密的明文,那么构造一个新的iv,iv’就变成了之前的密文块. 综上迭代就构造出了任意密文,因为iv可控.

利用脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from pwn import *
context.log_level = 'error'

plain =[['{', '"', 'u', 's', 'e', 'r', 'n', 'a', 'm', 'e', '"', ':', '"', 'a', '"', ','], ['"', 'e', 'x', 'p', 'i', 'r', 'e', 's', '"', ':', '"', '2', '1', '2', '2', '-'], ['1', '1', '-', '1', '1', '"', ',', '"', 'i', 's', '_', 'a', 'd', 'm', 'i', 'n'], ['"', ':', '"', 't', 'r', 'u', 'e', '"', '}', '\x07', '\x07', '\x07', '\x07', '\x07', '\x07', '\x07']]

def get_cipher(now, plain):
iv = list(16 * '\x00')
cipher = list(16 * '\x00')
middle = list(16 * '\x00')
for pos in range(15,-1,-1):
for t in range(256):
iv[pos] = chr(t)
success = False
attemp = 0
while attemp < 2 and not success:
try:
attemp += 1
sh = remote('2018shell.picoctf.com','6246')
sh.recvuntil('your cookie?\n')
except EOFError:
pass
success = True

sh.sendline((''.join(iv)+''.join(now)).encode('hex'))
sleep(0.03)
i = 0
while i<10:
try:
tmps = sh.recvuntil('\n')
break
except EOFError:
pass
if 'invalid' in tmps:
sh.close()
continue
if pos == 15: # this is a little test incase of that padding is 0x02 0x02
sh = remote('2018shell.picoctf.com','6246')
sh.recvuntil('your cookie?\n')
iv[pos-1] = chr(5)
sh.sendline((''.join(iv)+''.join(now)).encode('hex'))
try:
ans = sh.recv()
except:
pass
if 'invalid' not in ans:
iv[pos-1] = '\x00'
else:
continue
print 'hit', ((''.join(iv))+''.join(now)).encode('hex')
break

# middle equals chr(16-pos) ^ iv[pos]
middle[pos] = xor(chr(16-pos),iv[pos])
# change the iv to fit the next round
if pos == 0:
break
for k in range(15,pos-1,-1):
iv[k] = xor(middle[k],chr(16-pos+1))

# hit cipher
print 'success!'
cipher = [xor(xor('\x10',iv[i]),plain[i]) for i in range(16)]
print 'iv:',(''.join(iv)).encode('hex')
print 'ci:',(''.join(cipher)).encode('hex')
return cipher,iv



payload = ['\xba\xdeY\x10\x97d\xfe\xbe\xa2\xc7u\nM\xae\x94\xdc']

nt = list('\xba\xdeY\x10\x97d\xfe\xbe\xa2\xc7u\nM\xae\x94\xdc')
for pos in range(4):
tmp,iiv = get_cipher(nt,plain[3-pos])
payload.append(''.join(tmp))
nt = tmp
print 'finished\n\n'
print (''.join(payload[::-1])).encode('hex')

# ff68a8f849dabdf542891806a6b89337b563fab273a1c630dcb837cf6afdaddc212cfc95c3788fa5d0dacaa9a0aca60b0d703e74376e7863710c057471115544bade59109764febea2c7750a4dae94dc
文章目录
  1. 1. 写在前面
  2. 2. Padding Oracle
    1. 2.1. CBC Encryption
    2. 2.2. CBC Decryption
    3. 2.3. padding pcks7
    4. 2.4. 构造任意密文
    5. 2.5. 利用脚本
|