Nghĩ rằng làm gì thì làm, đầu tiên phải làm user = gg đã, thấy rằng có IV thì ta dễ dàng flip bit để return gg nhưng sau một hồi đặt bút mới nhận ra rằng P_new = gg rồi P_old làm gì có ? =)))
Lần này mình tự lừa mình ạ :( Thế là quay lại xem cái Token cho ở đầu xem như thế nào.
Ta thấy rằng nếu chỉ có token như này, chắc chắn sẽ vào đây
mà khi vào lookup thì như đã đề cập ở trên sử dụng Padding Oracle Attack ta sẽ recover lại được Token tức là P_old mà ta cần để tý flip bit đó xD.
Ok, xong rồi tiếp theo như nào ? Đi flip bit để user = gg luôn à ? Không ta để ý rằng sau khi user = gg ta phải nhập password nữa, vậy thì chi bằng ta tìm password trước rồi tý nhập 1 thể là xong.
try:
inp = input()
try:
user = parse(inp)
assert user == 'gg'
print('Welcome gg! Enter your secret passphrase:')
inp = input()
password = parse(inp)
if password == secrets['gg']:
print(flag)
Ta thấy nếu inp = E(token||gg, k) thì ta sẽ nhận lại được secrets['gg'], vậy còn chờ gì nữa mà không flip bit ? =))
Có được password rồi thì ta tiếp tục flip bit với inp = E(pad('gg',16), k) là có thể vào trong được rồi, sau khi vào thì nhập mật khẩu là lĩnh được flag thôi xD.
À mà quên đó cái password nó còn qua parse 1 lần nữa nên ta phải gửi inp = E(pad(password,16), k) nhé ! Má thảo nào làm mãi không ra (Mệt quá 5h hơn rồi T.T)
from pwn import *
from Crypto.Util.Padding import pad, unpad
def bit_flip_IV(IV_Old, P_Old, P_New):
IV_New = xor(xor(P_Old,P_New),IV_Old)
return IV_New
def padding_oracle_attack(block1, block2):
pt = [ord('.')]*16
for i in range(15,-1,-1):
fake_block1 = list(block1)
for j in range(15,i,-1):
fake_block1[j] = pt[j] ^ block1[j] ^ (16-i)
for j in range(256):
if j == block1[i] and i == 15:
continue
fake_block1[i] = j
ct = (bytes(fake_block1) + block2).hex()
r.sendline(ct.encode())
res = r.recvline().strip().decode()
if res == 'idk':
pt[i] = j ^ (16-i) ^ block1[i]
print(bytes(pt))
break
return bytes(pt)
r = remote('crypto.challs.pragyanctf.tech', 5001)
r.recvuntil(b':\n')
ct = r.recvline().strip().decode()
ct = bytes.fromhex(ct)
iv, block2 = ct[:16], ct[16:]
token = padding_oracle_attack(iv, block2)
print(f'{token = }')
# lookup : token||gg
s = unpad(token,16)+b'gg'
req = (bit_flip_IV(iv,token,pad(s,16)) + block2).hex()
r.sendline(req.encode())
password = r.recvline().strip()
print(f'{password = }')
#bypass user == 'gg'
s = b'gg'
req = (bit_flip_IV(iv,token,pad(s,16)) + block2).hex()
r.sendline(req.encode())
print(r.recvline())
#bypass password
req = (bit_flip_IV(iv,token,pad(password,16)) + block2).hex()
r.sendline(req.encode())
r.interactive()
Output :
b'...............\x03'
b'..............\x03\x03'
b'.............\x03\x03\x03'
b'............E\x03\x03\x03'
b'...........PE\x03\x03\x03'
b'..........RPE\x03\x03\x03'
b'.........2RPE\x03\x03\x03'
b"........'2RPE\x03\x03\x03"
b".......b'2RPE\x03\x03\x03"
b"......Kb'2RPE\x03\x03\x03"
b".....KKb'2RPE\x03\x03\x03"
b"....,KKb'2RPE\x03\x03\x03"
b"...O,KKb'2RPE\x03\x03\x03"
b"..WO,KKb'2RPE\x03\x03\x03"
b".'WO,KKb'2RPE\x03\x03\x03"
b"%'WO,KKb'2RPE\x03\x03\x03"
token = b"%'WO,KKb'2RPE\x03\x03\x03"
password = b'4^<iVqa?ERyb'
b'Welcome GG! Enter your secret passphrase:\n'
[*] Switching to interactive mode
p_ctf{4_l1ttl3_p4d4tt4ck_h3r3_&4_l1ttl3_x0r_THERE}
idk
[*] Got EOF while reading in interactive
Kinda_AESthetic
Source chall : Kinda_AESthetic.py
Hmm mới vào thấy bài sử dụng CBC và có pad, unpad là mình đã đoán ngay là có
Padding Oracle Attack rồi
Vậy là padding đúng sẽ return ra
idk
và padding sai sẽ returnidek
Nhưng theo bản năng mình vẫn đi tìm chỗ có flag trước :
Nghĩ rằng làm gì thì làm, đầu tiên phải làm user =
gg
đã, thấy rằng có IV thì ta dễ dàng flip bit để returngg
nhưng sau một hồi đặt bút mới nhận ra rằng P_new =gg
rồi P_old làm gì có ? =)))Lần này mình tự lừa mình ạ :( Thế là quay lại xem cái Token cho ở đầu xem như thế nào.
Ta thấy rằng nếu chỉ có token như này, chắc chắn sẽ vào đây
mà khi vào
lookup
thì như đã đề cập ở trên sử dụngPadding Oracle Attack
ta sẽ recover lại được Token tức là P_old mà ta cần để tý flip bit đó xD.Ok, xong rồi tiếp theo như nào ? Đi flip bit để user =
gg
luôn à ? Không ta để ý rằng sau khi user =gg
ta phải nhập password nữa, vậy thì chi bằng ta tìm password trước rồi tý nhập 1 thể là xong.Vậy việc tìm password như thế nào ?
Ta thấy nếu inp = E(token||gg, k) thì ta sẽ nhận lại được secrets['gg'], vậy còn chờ gì nữa mà không flip bit ? =))
Có được password rồi thì ta tiếp tục flip bit với inp = E(pad('gg',16), k) là có thể vào trong được rồi, sau khi vào thì nhập mật khẩu là lĩnh được flag thôi xD.
À mà quên đó cái password nó còn qua parse 1 lần nữa nên ta phải gửi inp = E(pad(password,16), k) nhé ! Má thảo nào làm mãi không ra (
Mệt quá 5h hơn rồiT.T)Output :