Rating:

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).