Padding Oracle攻撃をする問題らしい。  
以下Padding Oracle攻撃自体の説明はしない。  
より詳解している所で学習することを勧める。

> hint 1: login page grants access to a user with the credentials "guest" for
> both the username and password.

guest:guestでログイン可能らしいので、ログインする。  
cookieを見ると`token=fo39v%2FbeY1IAAZZpwmHSIpJmRYL0z%2BjmRL8P6g7pWgLeIuxvjxSoOA2cAZQRmNtN`となっている。  
変なtokenを提出してみると`error:1C800064:Provider routines::bad decrypt`と言われる。良さそう。

> hint 2: token structure: {"user": ""}

ということで、今回のcookieは`{"user": "guest"}`になっているということ？  
guest:guestでログインした後の画面に

> In order to escape from matrix you sould become Top-G  
> in other words you should login as topg

とあるので`{"user": "topg"}`を作ればよさそう。  
ブロックサイズが16とすると、`{"user": "topg"}`は15bytesなので、パディングを入れると`{"user":
"topg"}\01`のようになるはず。  
tokenのサイズを見ると、48bytesなので、どんな感じに入っているかは分からないが、32bytesで足りそうではあるので先頭にIVがくっついているんだろう。  
よって、`token = [IV 16bytes] + [enc1 16bytes] + [enc2 16bytes]`になっているはず。  
今回作りたい`{"user":
"topg"}\01`は16bytes分の1block分で事足りるので、tokenの末尾16bytesを削っておき、検証に利用する事にする。  
Padding Oracle攻撃を単純に適用すればいい問題なので後は実装を頑張る。

```python  
from tqdm import tqdm  
import struct  
from Crypto.Util.strxor import *  
import binascii  
import base64  
import requests  
import urllib.parse

BASE_URL = 'https://matrix.uctf.ir'

def check(c): # bytes -> bool  
c = base64.b64encode(c)  
c = urllib.parse.quote(c)

t = requests.get(BASE_URL + '/profile', cookies={  
'a07680ed6e93df92c495eaba7ddfe23b': 'eb81b14c5e5d7d24307dfde6d29f57d1',  
'token': c}).text  
  
ret = 'error:1C800064:Provider routines::bad decrypt' not in t  
return ret

def rewrite(enc, aim, bsize):  
assert len(enc) % bsize == 0  
  
num_block = len(enc) // bsize  
for i in range(num_block):  
print(b'[block ' + str(i + 1).encode() + b'] ' + enc[i*bsize:(i+1)*bsize])

num_aim_block = len(aim) // bsize

res = enc[(num_block - 1)*bsize:num_block*bsize]  
curr_block = enc[(num_block - 1)*bsize:num_block*bsize]  
for idx_block in range(num_aim_block):  
dec = b''  
for i in tqdm(range(bsize)):  
for j in tqdm(range(256)):  
payload = b'\x00' * (bsize - i - 1 + (num_block - 2 - idx_block)*bsize) +
struct.pack("B", j) + strxor(struct.pack("B", i + 1) * i, dec) + curr_block  
if check(payload):  
dec = strxor(struct.pack("B", i + 1), struct.pack("B", j)) + dec  
break  
assert len(dec) == i + 1  
curr_block = strxor(aim[(num_aim_block - 1 - idx_block)*bsize:(num_aim_block -
idx_block)*bsize], dec)  
res = curr_block + res  
res = enc[0:(num_block - (num_aim_block + 1))*bsize] + res  
return res

enc = 'fo39v/beY1IAAZZpwmHSIpJmRYL0z+jmRL8P6g7pWgI='  
enc = base64.b64decode(enc)  
res = rewrite(enc, b'{"user":"topg"}\x01', 16)  
res = base64.b64encode(res)  
print(res)  
```

こうしてできたtokenをcookieに入れて`GET /profile`するとフラグが得られる。

Original writeup (https://blog.hamayanhamayan.com/entry/2023/09/04/232413).