Welcome! This repository serves as a documentation hub for my journey into reverse engineering, binary exploitation, and malware analysis.
The top-level categories in the sidebar (such as Nightmare) act as markers to organize my writeups by platform/course.
This section features a collection of writeups for "Nightmare", a hands-on CTF centered course focused on reverse engineering and binary exploitation.
For more context on the course, visit the official project page: guyinatuxedo.github.io
This section introduces some beginner challenges with the goal of reverse engineering the flag.
pico ctf 2018 strings
I guess using strings is the "Hello World" of reverse engineering, as this challenge was a straightforward solve.
I checked the file permissions to see if the binary was executable and noticed the file size was larger than I anticipated.

I ran strings on the binary, and sure enough, a massive amount of filler text came up.


That's a lot of text. For context, wc -l prints the newline count, while -w prints the word count.
Next, I used grep to search for the flag. After looking up the picoCTF flag format, I found it typically starts with "picoCTF". For good measure, I used grep with the -i flag to ensure a case-insensitive search.

Success!
helithumper re
Let's run the binary and see what kind of input it expects.

It looks like it takes a string and checks for a match. Let's open it up in Binary Ninja for some static analysis.

In the main() function, we can see that validate() is called with the input string, and the program fails if validate() returns 0.
I switched the Binary Ninja output to "Pseudo C" and cleaned up the variable names. Let's break down the logic in the validate() function.

At the top we can see all the variables being set, including the flag, but let's ignore that for now and keep reading the code.

Here, we have while loop that uses i as the index counter.
The first if block checks whether the loop has reached the end of the string. If it has, it sets result = 1, meaning the input matches the flag.
(Remember, the if check in main() fails if validate() returns 0).
The second if block checks if the current character of the user input matches the character at the same index of the flag. If there is a mismatch, the function sets result = 0.
Finally, the i variable is incremented by 1 so the next character can be tested.

This is a stack canary. It helps prevent a buffer overflow by aborting execution if the variable is overwritten. With that, we have our flag and the end of the validate() function!
As a bonus, let's look the validate() function from an assembly perspective.

Here, we can see the string being constructed on the stack, with the characters represented in hexadecimal format. Let's use echo and xxd -r -p to convert this to ASCII in the terminal.
(Note: I added 0a at the end so the terminal outputs a newline).

Success!