Reversing ELF

Crackme1

To get the first flag we just need to run the binary. But first we need to give it permissions to run with chmod +x crackme1.

Crackme2

The second crackme asks for a password as an argument. If the password is wrong it outputs "Access denied".

Running the strings command reveals us the super secret password.

Now we can run the binary with the super secret password as argument to get the flag.

Crackme3

This crackme, as the previous one, asks for the right password as the its first argument.

Running the strings command on the binary reveals an base64 encoded string.

Decoding the string gives us the flag.

Crackme4

This crackme is similar to the previous ones, where you need to provide a password as an argument, but this time when we run it, it outputs a message saying that the string is hidden and that it uses strcmp.

If we see the man page of strcmp, with the command man strcmp, we can see in its description that it compares two strings a returns 0 if they are equal.

To solve this and the rest of the crackmes I will use radare2.

We can start the binary in debug mode with radare using the command r2 -d crackme4. Then we analyze the binary with the command aaa and check for its functions with afl.

We see that the binary runs a lot of function, but the most important here and in most binaries is the function main. We can analyze the main function running pdf @main.

Analyzing the main function shows us a lot of assembly code that we can ignore for now, what is important for us is that the main function calls another function, sym.compare_pwd, before it returns. We can analyze this function with the command pdf @sym.compare_pwd.

Once again, we can ignore much of the assembly code and focus only on the important instructions of this function. As stated before, this binary runs strcmp to compare two strings. Here we can see the strcmp at the address 0x004006d5. It will compare the string in the register rdi with the string the register rax. If both strings are equal, it will set the 32bit eax to 0 and return the "password ok" message. The register rax holds the input we used as an argument, so what we need to know is the string that rdi holds before the function executes the strcmp. To do that, we set a breakpoint at the address of the instruction mov rdi, rax with the command db 0x004006d2. Then, we execute the program with dc until it reaches the breakpoint and stop. Since we need to provide an argument with the program, we cad run ood 'argument', and then set the breakpoint and run it (the string we use doesn't matter).

Now we've reached the breakpoint. To do know the value of rdi we type px @rdi.

We revealed the content of rdi before the strcmp, and we can check that it is indeed the correct password by running the binary with it as argument.

Crackme5

This binary asks for user input instead of of arguments.

Once again lets debug it with radare2 and disassemble the main function.

At the beginning of the function we see a different character assigned to each variable. Although quite troublesome, if we just assembled all this characters in a single string we would find out that the answer was always exposed to us.

We have once again a strcmp, this time in the main function. As before, we set a breakpoint before the strcmp, which compares the registers rdi and rax. This time, rdi doesn't store anything of value for us, but if we investigate the rsi register, we see that its content is the same characters assigned to each variable at the beginning of the main function.

If we use this string as the input we get the "Good game" message.

Crackme6

Crackme6, like other previous crackmes, asks for a password as argument.

Let's analyze the main function.

Once again let's focus on the essential instructions of the function. What caught my attention here is the sym.compare_pwd, so let's analyze it.

We can see that it is in this function that the password is checked with our input, but we can't know what our input is actually being compared to because that value comes from the sym.my_secure_test function. So let's take a look at it.

Ok! This function is too big for a single screenshot, and its really hard to analyze with all those jumps on it in text mode. This where graph mode comes in handy. To enter graph mode just type vV. Once in graph mode we can use the same commands as in text mode, but we need to start them with : instead.

Graph mode makes things more clear. We can see that this function compares the least significant 8 bit of the rax register ( al) with some hex value, then if its equal it increments the rax register and compares it again with another hex value. It seems that it is comparing every char in our input with these hex values.

If we join all these values together and decode them into their ASCII equivalent we get the password to solve the crackme.

We can confirm it is the right password by running the binary.

Crackme7

When we execute this binary it has a basic interactive console where we can say hello and add numbers.

Like always we start by analyzing the main function.

The interesting part of this function is where the string "Wow such h4x0r" is called. This string is called after eax is compared to 0x7a69. If we decode it to its ASCII equivalent and try to use it as input it displays the message "Unknown input!".

But if we decode it to decimal and use it as input, it reveals the flag.

Crackme8

Crackme8 also takes the password as argument.

The first step is top run the binary on radare2 and analyze the main function.

Here we see two interesting instructions. The first one is the call of the atoi function. A quick look at atoi's man page shows us that this function will convert our input string to an integer.

The other instruction is the compare of eax with the cafef00d. If the eax is equal to this hexadecimal value the function will print the "Access granted" that we are looking for. If we try to convert the string to its normal decimal value we get 3405705229, but once we use it as input we get the "Access denied message". Converting this hex value to binary shows that its most significant bit is 1, so the value represented is actually negative. Using an online converter we can get this negative value.

Using it as input gives us the flag.

Last updated