Cat Simulator
Cat Simulator
Platform: Broncoctf2026 | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-11 | Status: Solved Techniques: decoy_elimination, dynamic_verification, state_predicate_recovery, static_disassembly
Summary
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.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
broncoctf2026| ID:20260711_broncoctf2026_cat_simulator - Tags: state_machine, decoy_flag, arm64, ctfd_download, macho, branching_game
- Indicators: plaintext decoy flag bonco{almost_there}, 5-day branching choice game, cross-platform standalone binaries, flag gated behind score/count/length state check, CTFd signed URL returns 403 without browser User-Agent/Referer
- Source:
20260711_broncoctf2026_cat_simulator.md
Foothold
Vulnerability / Misconfiguration
- Decoy_elimination
- Dynamic_verification
- State_predicate_recovery
- Static_disassembly
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- decoy_elimination
- dynamic_verification
- state_predicate_recovery
- static_disassembly
- Tags: state_machine, decoy_flag, arm64, ctfd_download, macho, branching_game
Original Writeup
<details><summary>Click to expand original content</summary>Description
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.
Recon
- The challenge ships the same game as three self-contained executables — a classic sign of a cross-platform build with the win logic embedded in native code rather than in packaged asset files.
- CTFBase semantic search returned only a generic visual-novel XOR precedent
(
20260115_duckerz_novella) — no direct match, so this had to be reversed from scratch. - CTFd download tip: the CTFd signed download URLs returned HTTP
403with plaincurl. Adding a browserUser-Agentand aReferer(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>'
Analysis
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):
- invalid count == 0
- talk count == 3
- scratch count == 1
- eat count == 1
- final score == 45 (
3*25 - 50 + 20 = 45) - hidden mood >= 1 (deterministically 21 for these counts:
3*7 - 12 + 2 = 11… mood accumulates to a positive value) - sum of the three talk-message lengths == 32
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.
Solution
Satisfy every predicate simultaneously:
- Make exactly 3 talks, 1 scratch, 1 eat over the 5 days — the
choice sequence
1, 1, 1, 2, 3. - Make the three talk messages total exactly 32 characters. Message lengths
10 + 10 + 12 = 32work. - Never enter an invalid choice.
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}
</details>
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR