$ cat writeup.md…
$ cat writeup.md…
asisctf2026
Task: reverse a remote worker that accepts hex-encoded bytecode for a tiny custom VM guarded by a seed-based capability check. Solution: recover the RUN parser, VM opcodes, and initial register state, then send a minimal six-word program that copies the seed, computes its fmix64 value, and triggers the flag gate.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
speaks in mysterious bytes
guards its secrets like a dragon
answers every mistake with the emotional range of a toaster
We are given a downloadable challenge bundle and a remote worker at nc 91.107.151.102 18113. The service is not a memory-corruption target; it is a strict text protocol that decodes a hex payload into a small custom VM program.
Connecting to the service and sending INFO returns the banner:
RB/2 release=fe753d7fdd51acc3b3a23109 words=64 regs=8
Static reversing of revenant-worker showed that the worker accepts only three commands:
INFORUN <hex>QUITRUN requires a non-empty even-length hex string with a maximum of 0x200 characters. The bytes are decoded, grouped into 4-byte little-endian words, and then transformed into internal VM words before validation and execution.
The executor starts with:
r0..r6 = 0 r7 = seed typestate = [0,1,1,1,1,1,1,2]
The important recovered opcodes were:
0xce dst, imm15 → reg[dst] = imm150x2f dst, src, rot6 → reg[dst] = rol64(reg[src], rot6)0x8d dst, src → reg[dst] = fmix64(reg[src] ^ 0x0ae7854d6e616ef3)0xd9 dst, a, b, imm15 → reg[dst] = ((imm15 + 1) * reg[b]) ^ reg[a]0x9e seedReg, hashReg → checks reg[seedReg] == seed and reg[hashReg] == fmix64(seed ^ 0x0ae7854d6e616ef3), then opens flag0xdc → haltBecause r7 already contains the per-connection seed and r0 is zero, the shortest useful program is just: hash r7, copy the seed into a type-accepted register, copy the hash into another type-accepted register, call the capability gate, then halt.
The minimal valid transformed words were:
0xefc6ab35 0x0000398d 0x00023fd9 0x000209d9 0x00000f9e 0x000000dc
One valid raw preimage for those words was:
0xe9cf8542 0x075782d1 0x30e082c0 0xc8befb7a 0x975f3e1d 0xd381cb3b
...
$ grep --similar