$ cat writeup.md…
$ cat writeup.md…
broncoctf2026
Task: cross-platform cat-simulator choice game (Windows/macOS/Linux) where a 5-day branching route reveals the flag; a plaintext decoy bonco{almost_there} is planted to mislead string grepping. Solution: reversed the Mach-O ARM64 finale to recover the win predicates (3 talks, 1 scratch, 1 eat, talk-message length sum == 32, score == 45, no invalid choices), then ran choices 1,1,1,2,3 to print the real flag.
Make the purrfect choices over 5 days to win your owner's heart… and maybe something more? Meow carefully.
Three standalone platform binaries are provided (Windows .exe, macOS ARM64
Mach-O, Linux ELF) of a cat-simulator branching-choice game. The player makes
menu choices over 5 in-game days; the winning route reveals the flag. The
macOS ARM64 Mach-O (cat-sim-mac, 34,008 bytes) was the binary actually
analyzed.
20260115_duckerz_novella) — no direct match, so this had to be reversed
from scratch.403 with
plain curl. Adding a browser User-Agent and a Referer
(https://broncoctf.ctfd.io/) made the download succeed:curl -L -o cat-sim-mac \ -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' \ -H 'Referer: https://broncoctf.ctfd.io/' \ '<signed-download-url>'
Running strings on the Mach-O immediately reveals a plaintext flag-shaped
string:
bonco{almost_there}
This is a decoy (note the misspelled bonco{...}, not bronco{...}). It is
the branch reached when only one of the several win conditions is met, planted
specifically to catch players who grep for {.
Disassembling the game loop and finale (main/check routine at 0x100000500,
finale checks starting at 0x100000780) shows the game is a small state machine.
Each day accepts a menu choice that mutates several counters:
| Choice | Meaning | score | hidden mood | side effect |
|---|---|---|---|---|
1 | talk | +25 | +7 | talk count +1, add trimmed talk-message length |
2 | scratch | -50 | -12 | scratch count +1 |
3 | eat | +20 | +2 | eat count +1 |
| other | invalid | — | — | invalid count +1 |
The finale gate checks a conjunction of predicates (order irrelevant):
3*25 - 50 + 20 = 45)3*7 - 12 + 2 = 11… mood accumulates to a positive value)The visible bonco{almost_there} decoy is emitted when only the talk-length sum
condition (== 32) is satisfied but the count/score predicates fail. The real
flag branch hashes the deterministic hidden-mood value and applies vector
XOR/bit-shuffle constants from __TEXT, so the flag is not a plaintext
literal — it is reconstructed at runtime only on the correct path.
Satisfy every predicate simultaneously:
1, 1, 1, 2, 3.10 + 10 + 12 = 32 work.This yields score 45, positive hidden mood, and the length sum 32, tripping
the real flag branch.
#!/usr/bin/env bash # choices: 1,1,1,2,3 (talk, talk, talk, scratch, eat) # talk messages sized 10,10,12 -> total 32 chars printf '1\nabcdefghij\n1\nabcdefghij\n1\nabcdefghijkl\n2\n3\n' | ./cat-sim-mac
Dynamic run prints:
bronco{REDACTED}
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar