┌───────────────────────┐
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
│                       │
└───────────────────────┘
moooo — BYUCTF 2025
~ Imattas aka Zemi
 Category: Reverse Engineering
 Author: Imattas aka Zemi
 Flag: byuctf{moo_mooo_moooo_mooooooo_moo_lol}
 Source Path: rev/moo

────────────────────────────────────────────────────────────────────────────────

--[ Challenge Description ]--
-- text --
### Description

Moo, mooo mooo mooo. Mooo mooo moooo moo moo moooooooooo moo moooo
(When you have the flag, the program will run printing "gotem")

Files:
- [main.cow](https://github.com/BYU-CSA/BYUCTF-2025/blob/main/rev/moo/main.cow)
────────────────────────────────────────────────────────────────────────────────

--[ Provided Materials ]--

- Repository folder https://github.com/BYU-CSA/BYUCTF-2025/tree/main/rev/moo
- rev/moo/README.md
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/rev/moo/README.md

────────────────────────────────────────────────────────────────────────────────

--[ Recon / Initial Analysis ]--

This page imports the BYUCTF 2025 source material for the Reverse Engineering
challenge moooo. The prompt is kept separate from the solve notes, and upstream
artifacts are linked so the challenge can be replayed from the original
repository.

────────────────────────────────────────────────────────────────────────────────

--[ Vulnerability / Observation ]--

The useful observation comes from the imported solve notes below. I kept the
original technical path intact while normalizing the page metadata, challenge
grouping, and author attribution for the Volume 2 writeup archive.

────────────────────────────────────────────────────────────────────────────────

--[ Exploitation / Solution ]--

Source: rev/moo/README.md
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/rev/moo/README.md

This challenge is in a language called COW, which is documented on the esolang
wiki https://esolangs.org/wiki/COW and is just awful. I had a deep dive into it
because I found it on a google spiral and decided to really dive into it. There
are only 12 instructions in the whole language, as documented on the site:

Opcode  Description
moo                                   This command is connected...
mOo     Moves current memory posi...
moO     Moves current memory posi...
mOO     Execute value in current ...
Moo     If current memory block h...
MOo     Decrement current memory ...
MoO     Increment current memory ...
MOO     If current memory block v...
OOO     Set current memory block ...
MMM     If no current value in re...
OOM     Print value of current me...
oom     Read an integer from STDI...


My personal approach with a challenge like this is starting to redefine the
opcodes as something that I can understand. There's a file in this directory
(main-commented
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/rev/moo/main-commented) that
contains the commented original code before it was turned into an amalgamous
blob. For a dynamic approach, it's really useful to have a small interpreter
such that you can print debug information. Usually, I'll reverse the program
until I understand it enough to debug and that will take me the rest of the way
there.

For the process of static RE, I usually start with separating the program on
useful lines. The program starts with this: MoO MoO MoO MoO MoO MoO MoO MoO MoO
MoO MoO MOO. This increments the first space of memory by 11 and starts a loop.

That loop processes these commands (skipping the first the first time):
moO MoO MoO MoO MoO MoO MoO MoO moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO moO 
MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO moO MoO MoO MoO MoO moO MoO MoO MoO moO MoO mOo mOo mOo mOo mOo mOo MOo
Each piece of this can be separated on moO, which moves +1 memory block:
moO MoO MoO MoO MoO MoO MoO MoO
moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO
moO MoO MoO MoO MoO MoO MoO MoO MoO MoO MoO
moO MoO MoO MoO MoO
moO MoO MoO MoO
moO MoO
mOo mOo mOo mOo mOo mOo MOo
The loop will increment each space of memory by a certain amount in a loop. MOO
will loop until the memory address it's on is 0. So it'll loop 11 times, since
that's what our first piece set. So memory after the loop is finished will be:
0 77 110 110 44 33 11

After that, we have another section of commands, before we get to the OOO:
moO Moo moO 
MoO Moo Moo moO moO MoO MoO Moo moO MOo Moo mOo mOo mOo mOo Moo moO Moo Moo moO moO moO Moo mOo mOo MOo Moo mOo Moo Moo moO moO 
moO Moo mOo mOo Moo mOo Moo Moo Moo moO moO moO MoO Moo moO MOo Moo moO
This can be split up by the print statements (Moo) and memory moves (moO/mOo) as
follows:
moO Moo ; 77
moO MoO - Moo Moo ; 111 111
moO moO MoO MoO - Moo ; 46
moO MOo - Moo ; 32
mOo mOo mOo mOo - Moo ; 77
moO - Moo Moo ; 111 111
moO moO moO - Moo ; 32
mOo mOo MOo - Moo ; 109
mOo - Moo Moo ; 111 111
moO moO moO - Moo ; 32
mOo mOo - Moo ; 109
mOo - Moo Moo Moo ; 111 111 111
moO moO moO MoO - Moo ; 33
moO MOo - Moo ; 10
moO
Tracking from our original memory of 0 77 110 110 44 33 11, this prints 77 111
111 46 32 77 111 111 32 109 111 111 32 109 111 111 111 33 10 as their ascii
values. In a Python repl, we can print that out ourself!
-- sh --
➜  moo > python 
>>> values = '77 111 111 46 32 77 111 111 32 109 111 111 32 109 111 111 111 33 10'.split()
>>> ''.join([chr(int(i)) for i in values])
'Moo. Moo moo mooo!\n'
That's more or less the static reverse engineering side of things! You can just
continue that process until you find the flag, paying attention to those 'break
spots', especially as you understand the language more.

For the dynamic side, I spent a long time looking for a good online interpreter,
and there are a few that can interpret https://frank-buss.de/cow.html but none
that do stdin in the way I wanted (allowing you to input more than one character
at a time) as far as I could find. Luckily, there are only 12 opcodes so
actually implementing an interpreter myself was pretty easy, though I'll change
it to use sys.stdin in Python for input if I ever go back and edit it. That
interpreter is in moo.py
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/rev/moo/moo.py, and you can add
debug statements to it so that you can visualize what the program is actually
doing.

The program itself is designed to only complete all the way to the end under one
flag. It'll run by taking your input into various memory slots and then subtract
a lot off each spot followed by the mOO opcode to 'execute' whatever value is in
memory at that location. This would only allow the program to finish if moO or 3
was in that memory location, so you can statically reverse the program to add 3
to the number of subtraction operators at each check OR many people in the
actual CTF side channelled the program since it would kill itself if the input
was not correct. There is a Moo compiler somewhere online so people used that to
output an actual program and then side channeled that binary. I was also told
that AI could make a pretty decent little interpreter, too.

All in all, a fun challenge, and it will print gotem when you get the actual
flag! It was a fun one to make and to work through to solve as well.

Flag : byuctf{moo_mooo_moooo_mooooooo_moo_lol}

────────────────────────────────────────────────────────────────────────────────

--[ Full Exploit Script ]--

No standalone exploit script was present in the selected source material.

────────────────────────────────────────────────────────────────────────────────

--[ Key Takeaways ]--

- The BYUCTF 2025 challenge material is preserved with local archive formatting.
- The page author is normalized to Imattas aka Zemi.
- The source repository remains linked for handouts, services, and solve
artifacts.