$ cat writeup.md…
$ cat writeup.md…
avitoctf
Task: Forge an XMSSMT-MD5 authentication token for beekeeping expert kopatych and recover a hidden post. Solution: Reuse chosen-message WOTS chain elements from repeated index-0 signatures and splice a valid target signature.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
The service is a beekeeping-themed social network using post-quantum XMSSMT-MD5 signatures as authentication tokens. The goal is to forge access to the expert account kopatych and retrieve the hidden location or post from its VIP wall.
Registrations accept a chosen nickname and return a HoneyPass containing an XMSSMT signature followed by that nickname. A valid token logs the user into the profile named by the signed message.
The supplied implementation initializes XMSSMT-MD5 with:
n = 16 bytes;w = 256;h = 32;d = 4 XMSS layers, each of height 8;For the bottom layer at index 0, the WOTS message is the 16-byte digest
MD5(be32(2) || R || root || be128(index) || username)
Because w = 256, each digest byte is directly one WOTS chain length. The first 16 lengths are the digest bytes. The checksum is
checksum = sum(255 - digest_byte)
and its two bytes, encoded big-endian, are the final two chain lengths.
xmssmt_sign_message() calls xmssmt_core_sign(), but that core function only prepares a signature; it does not advance the secret-key state itself. The wrapper xmssmt_update_signing_key() exists and calls xmssmt_update_sk(), but there is no caller anywhere in the service.
Consequently, ordinary sequential registrations all sign at XMSS index 0. They reuse the same randomizer R, bottom WOTS one-time key, authentication paths, and upper-layer signatures. This is a deterministic state-management failure, not a race condition. No concurrent requests are required.
...
$ grep --similar