CTF Circle - Hack-A-Sat 2021 Qualifier CTF
tree in the forest Challenge Writeup
Written by sen (@sarahemm)

###############
### Summary ###

The "tree in the forest" challenge listed a server and port number only, gave a
file named parser.c, and instructions on how to compile it. There was no
information given about what the goal was beyond getting the flag.


############################
### Tools/Infrastructure ###

Our team has a couple servers we use as a launching point for CTF work,
so my work was done on these. No other tooling was needed other than
Ruby, which is the primary language I prefer for challenges like this,
but it could have equally been done in essentially any other language.


###########################
### Phase 1 - Discovery ###

To start off, I connected to the provided IP/port with netcat to see what the
challenge was in the first place. It gave me "Starting up Service on
udp:[ip]:[port] and nothing else.

Looking at the source for parser.c, comments at the top indicated that it
logged how many times each command was hit, and had a security feature to
hide the flag from the user. It appeared that this program was what was
running on the UDP port provided when connecting to the challenge.


###############################
### Phase 2 - Investigating ###

Looking through the source code provided, it seemed to want commands as 8
bytes: a short/2-byte version number, a short/2-byte type, and an int/4-byte
command ID. The first 2 fields were essentially ignored, but the latter seemed
important. Upon receiving a command ID, the code would increment a counter for
that ID stored in an array, then pass a message back over UDP indicating that
the command had succeeded. If the command was the 'get keys' command, it would
be rejected unless the 'lock' had been unlocked previously, in which case it
would provide the flag. There was no provided functionality to be able to lock
or unlock this over the UDP port.

Having the source code made finding the vulnerabilities easier than it would
otherwise have been, and looking through it a few things stood out. First, the
check to ensure only valid commands were received only checked that the command
ID wasn't higher than the maximum command ID, but there was no check for a
lower bound. Some fprintf statements had been commented out that showed the
address of where the array of counts was stored as well as where the
lock_state variable was stored, indicating that this was likely where the
overflow would be.


#########################
### Phase 3 - Solving ###

Uncommenting the fprintf statements and looking at the addresses, the
lock_state variable was 8 bytes below the start of the command log. Given the
lack of a lower bound check on the commands, it seemed like we could pass -8
for the command ID many times, incrementing the lock_state variable so many
times that it went from 1 (locked) all the way around to 255 and back to 0
(unlocked), at which point sending a 'get keys' command would give the flag.

I threw a quick Ruby script together to send 254 commands of type -8 to unlock
the security lock, then send a command of type 9 to get the flag. Running this
against my local copy of the parser tool showed that it was still locked since
I was one short on the unlocking loop, oops. Fixing this to 255 commands
resulted in the flag coming out, and running this against the real challenge
gave the real flag.

############
### Code ###

The script used to solve this challenge is at https://github.com/sarahemm/ctf-tools/tree/master/2021-hackasat/tree_in_the_forest.