$ cat writeup.md…
$ cat writeup.md…
umdctf
Task: a stripped ELF self-decrypts a hidden code section, validates a base64 ticket through a custom VM, and processes an encrypted market feed archive. Solution: decrypt .xtext, decode the double-encrypted feed, recover the VM semantics and true ticket input source, solve the eight dword constraints with Z3, and use the derived 32 bytes as AES key plus IV to decrypt the final record.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
No separate organizer description was present in the provided workspace files.
English summary: the challenge ships a stripped ELF named oracle plus an encrypted feed.bin. The binary behaves like a market-settlement verifier: it reads a base64 ticket from ticket.txt, validates the decoded 32-byte body with a custom VM, derives 32 bytes of key material on success, and uses that material to decrypt the final archive record containing the flag.
At a high level, the solve path was:
.xtext code that main unseals at runtime.feed.bin, which needs two outer decrypt passes before an ARC\x01 archive decode with a rolling XOR stage.b and fix the critical misunderstanding about where the 32-byte ticket body is actually read from.AES-128 key || IV to decrypt record g.The useful local artifacts created during solving were:
decrypt_xtext.pypatch_oracle.pydecode_strings.pydecode_feed.pyemulate_crypto.pyrun_vm.pysolve_ticket.pyThe ELF is a stripped PIE x86-64 binary with a hidden encrypted section named .xtext. The visible main function is mostly a loader:
chk section with seed 0xc0def1ab.rodata.rodata.xtextThe important detail is that the hidden section is not plain AES or TEA-CBC. It is a TEA-based CFB-like stream mode:
...
$ grep --similar