| 题目描述如下: 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}
 
 |