umdmarket
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.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
umdmarket — UMDCTF
Description
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.
Analysis
1. Recon from the frontend bundle
The first useful finding was not in the visible UI, but in the shipped client bundle.
/docs/llmswas a decoy./docscontained the real protocol documentation.- the frontend also exposed the exact WebTransport endpoint and certificate pin.
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.
2. Reconstructing the protocol
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:
- server streams signed quotes,
- client may trade only by replaying one of those quotes,
- stale quotes are rejected when older than
MaxAge = 5ticks.
...
$ grep --similar
Similar writeups
- [web][free]live-signal— umdctf
- [web][free]rainbet— umdctf
- [pwn][free]velvet-table— umdctf
- [web][Pro]UUIDY— duckerz
- [network][free]security-breach-ruin— umdctf