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.