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.

alt text

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

alt text

alt text

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.

alt text

Success!

helithumper re

Let's run the binary and see what kind of input it expects.

alt text

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

alt text

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.

alt text

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.

alt text

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.

alt text

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.

alt text

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).

alt text

Success!