$ cat writeup.md…
$ cat writeup.md…
avitoctf
Task: A social network issues XMSS-MT authentication tokens and restricts an expert's full wall to VIP users. Solution: Reused index-zero WOTS+ chains were advanced coordinate-wise to forge a valid token for the VIP account.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
A social network hides honey expert kopatych's exact location from non-VIP users. A TCP service and its C source archive are provided, together with an invite code.
The goal is to authenticate as the existing VIP user kopatych and read the full wall post. The service issues a hexadecimal XMSS-MT signed-message token whenever a new nickname is registered.
register_user() stores a non-VIP account and signs the raw username. A token is simply the XMSS-MT signed-message byte string encoded as hex. During login, the server verifies the signature, recovers the appended username, and loads that user's database record. Consequently, a valid signature over kopatych grants a session with the existing account's VIP bit; no separate role field needs to be modified.
The decisive source-level bug is in commands.c: registration calls xmssmt_sign_message() but never calls xmssmt_update_signing_key(). Although the latter function exists and safely increments the shared secret-key index, the registration path leaves the state unchanged. Every registration therefore signs with global XMSS-MT index zero.
The supplied implementation uses these parameters:
| Parameter | Value |
|---|---|
Hash size n | 16 bytes |
Winternitz base w | 256 |
wots_len1 | 16 |
wots_len2 | 2 |
| Total WOTS+ coordinates | 18 |
XMSS-MT layers d | 4 |
| Full height | 32 |
| Per-layer tree height | 8 |
| Index size | 4 bytes |
| Signature size | 1684 bytes |
The signature layout is:
index (4) || R (16) || 4 * (WOTS+ signature (18*16) || auth path (8*16))
...
$ grep --similar