$ cat writeup.md…
$ cat writeup.md…
umdctf
Task: a browser prediction market exposed WebTransport protocol docs and HMAC-signed quote tokens for trading. Solution: abuse RESEND, which re-signed historical prices with the current sequence number, to replay stale favorable quotes as fresh ones and grind the balance above the flag threshold.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Predicting the future is now legal in all 50 states.
English summary: the challenge was a prediction market web app. We started with $100, needed to reach 10,000,000 internal units ($1000), and then call the flag purchase action. The intended defense was that every trade had to use a recent HMAC-signed quote, but the resend feature broke that freshness guarantee.
The first useful finding was not in the visible UI, but in the shipped client bundle.
/docs/llms was a decoy./docs contained the real protocol documentation.The service connected to:
https://umdmarket.challs.umdctf.io:4443/wt
with the embedded SHA-256 certificate hash:
ac02c9f7e1558563180ed412dedb9e793fd9b3ab36d64beb7e178283a68a4c9f
client_methods.txt made the binary client logic much easier to reconstruct. It showed the request opcodes, field order, and the fact that trades are not priced freely by the client. Instead, the client must echo back a server-issued signed quote.
The important packet types were:
| Message | Opcode | Fields |
|---|---|---|
QUOTE datagram | 0x01 | seq:uint16, ticker_id:uint16, yes_price:uint16, hmac[8] |
RESEND request | 0x26 | seq:uint16, ticker_id:uint16 |
TRADE request | 0x30 | seq, ticker_id, yes_price, hmac, side:uint8, qty:uint32 |
BUY_FLAG request | 0x50 | available once balance >= 10,000,000 |
The signed QUOTE datagram was the core security primitive. The docs described the intended model as:
MaxAge = 5 ticks....
$ grep --similar