题目描述如下: Pad with 2019 in 2020! Let your past go!
nc 207.148.119.58 5555 审计源码可知,本题需要我们连续完成2个任务,一个是解密token,从而拿到flag的前半部分;另一个是伪造token,从而拿到flag的后半部分。 在计算token时,先对msg进行pad,再进行AES-CBC加密;解密时先解密,再进行unpad,另外服务器端充当了一个padding oracle,可以告诉我们解密后的消息是否padding正确,根据这些特征很容易联想到CBC字节翻转攻击,关于CBC字节翻转攻击的细节可以参考这里。对于flag的前半部分,我们可以一字节一字节的恢复,从x00开始不断试错,如果收到报错提示,则尝试发送下一字节,否则就存储该字节;对于flag的后半部分,我们想要使得obj['admin'] == True,只需翻转fals为tru。将上述攻击过程写成python代码形式如下(flag前半部分): import json
from os import urandom
from pwn import remote, process
from string import ascii_letters, digits
from itertools import product
PAD = (("2019") * 8).decode('hex')
def get_paddings_dict(n):
ans = {}
for i in range(n):
ans[i] = pad(i+1)
return ans
def pad(n):
pad_length = n
return chr(pad_length) + PAD[:pad_length - 1]
def crack_byte(token, pos, i):
token[pos] = i
return ''.join('{:02x}'.format(x) for x in token)
def find_pad(r, token, pos, last_x):
token = bytearray(token)
padings = get_paddings_dict(pos+1)
if pos:
token[0] = last_x[0] ^ ord(padings[0][0]) ^ ord(padings[pos][0])
for j in range(1, pos):
token[j] = last_x[j]
for i in range(256):
payload = crack_byte(token, pos, i)
r.sendline(payload)
ans = r.recvline()
if i % 64 == 0:
print("current step: ", pos, i, ans)
if 'padding' in ans:
continue
else:
return i
raise Exception("All padings are incorrect")
if __name__ == '__main__':
r = remote("207.148.119.58", 5555)
token_hex = r.recvline(False)
print(token_hex)
token = token_hex.decode('hex')
parts = [token[i:i+16] for i in range(0, len(token), 16)]
known = "TF{***********"
flag = ''
exp_pad = pad(1)
c1 = parts[2]
c2 = parts[3]
last_x = []
for i in range(len(known)):
exp_pad = pad(i+1)
x = find_pad(r, c1+c2, i, last_x)
i2 = x ^ ord(exp_pad[i])
ch = chr(i2 ^ ord(c1[i]))
if i < len(known) and ch == known[i]:
flag += ch
print("Horay!", flag)
last_x.append(x)
else:
flag += ch
print("Is it right?", flag)
last_x.append(x)
print('TetC' + flag[:-2])
执行脚本即可得到前半部分flag: flag后半部分脚本如下: import json
from os import urandom
from pwn import remote, process
from string import ascii_letters, digits
from itertools import product
def crack(token):
test_token = bytearray(token)
test = b'x02 {"admin": fals'
for i, (x, y) in enumerate(zip(test, b'x01{"admin": true}')):
test_token[i] ^= ord(x) ^ ord(y)
return ''.join('{:02x}'.format(x) for x in test_token[:32])
if __name__ == '__main__':
r = remote("207.148.119.58", 5555)
token = r.recvline(False).decode('hex')
new_token = crack(token)
r.sendline(new_token)
r.interactive()
执行脚本即可得到后半部分flag: th3_b3g1nn1ng_d03s_n0t_h3lp}
拼接前后两部分即可得到完整flag: TetCTF{p4dd1ng_4t_th3_b3g1nn1ng_d03s_n0t_h3lp}
|