Crackme.c - A small reversing puzzle

(The Defalt) #1

What’s up everyone? It’s been quite a while. This is just going to be an easy little puzzle for you guys to play around with. I got bored in class so I decided to make a fake login in C.

There are 3 intended solutions to this, but those are for you to find out!

The code for the puzzle can be found here:

BUT! If you want to solve the puzzles without looking at the code first, just follow this:

I’ll have my 3 solutions in the spoilers below. Have fun!


Solution 1:

Buffer overflow

The first solution is the easiest. We can simply overflow the buffer used to store the given password to change the value of the “valid” integer to a non-zero number, which will evaluate to true when it’s checked.

Solution 2:

The second solution is a bit harder, but still pretty easy. We’ll start by using objdump on our executable to get the assembly for all of the funtions:

Now that we have this dump file, let’s take a look in it. We’ll scroll all the way down to the assembly for the main function. BUT, what’s this? Right above the main function we can see there is another function that is hidden from us:

But, if we look at the main function, this secret function is never called. But don’t worry, GDB to the rescue! We can changed the EIP to point to the secret function, and force it to execute:

Now if we let the program finish, we should see the output of the secret function:

Solution 3:

Our last solution is the largest pain in the ass out the 3. When we execute our login, the values are juggled around in the registers, as usual. BUT, using GDB, we can read these registers and find the password while it’s being tested.

To do this, we just start our login in GDB normally:

Now that we’re here, let’s disassemble this program and take a look at the assembly. Specifically, we’re going to look where the gets() function is called, and the instructions that follow it:

Here we can see that after gets() is called, there’s a lot of movement done with the EAX register. So, if we monitor the EAX register, we might be able to find something. We’ll use the display command to show whats in EAX every time we step through an instruction.

This is what a change in EAX will look like, that number to the right will change. Now, let’s step through our program until we’re prompted for a password, then we’ll start paying attention to this number:

Now that we’ve been prompted for the password, let’s keep an eye on EAX until it changes again:

There we go. Now, if we use “x/s” to convert to contents of the address currently stored in EAX to a string, we should have the password for our login:

Challenge Collection: Reverse Engineering and CrackMe
(Ne0_) #2

Nice little Challenge. Looking forward for more!

Here’s my solution:

First, i disassembled the main function:

At 0x0804859b we see a value compared to 0, if equals, a few instructions are jumped over. My guess: DWORD PTR [ebp-0xc] is a “boolean” value that is 1 if the entered password is correct.
To prove this hypothesis:

A comparison, followed by a jump if not equal. BUT, if it is equal, our old friend DWORD PTR [ebp-0xc] is set to 1 (my guess: password correct).

So, I set a breakpoint just before the boolean “password correct” value is checked:

Get the address of the ebp register:

Subtract 12, because our pointer is -0xc (hexadecimal for 12) in regards to ebp. So our “password correct” “boolean” lies at 0xfffcecc.

So I check the value, it is indeed 0. Then I just set it to 1, so the next instructions thinks the password I entered has been correct, et voilà:

Tbf, I didn’t get the password in this scenario. BUT, I logged in, and that’s something at least, right?

edit: Thanks @oaktree for setting the spoiler tags. Sorry, totally forgot about that.


Simple solution:

My solution was to find the offset of the read only data section then export all strings in that section.

(Austin) #4

Been trying out binary ninja demo.
Made this very easy…

opened the binary and saw the secret function looked at the hex for the function and found the password

(We're all just code) #5

This feels like cheating, but…

The password is: Rev3ngineering1sc00l!
Enter the password! 
Checking password...


Hello, I tried another two solutions.

The first one is similar that the first one of @Defalt solutions.

I use buffer overflow too, but instead of overwritting the “valid” variable, I use the shorten input and overwrite only the original password.


Checking password...

Successfully logged in!
Good job!

The second solution uses different approach then other solutions in this thread.

It is possible to use buffer overflow vulnerability and exploit the binary. It is possible to achieve execution of “secret” function via entered password. Just enter looong password and overwrite the stored return address from main function in stack.
On modern systems with ASLR enabled and with crackme compiled with gcc from @Defalt post, it can be a not so easy to overwrite the stored return address (eip). Maybe you noticed the difference between prologue and epilogue of main and secret functions.
If you want to play with this exploit, I recommend you to temporary disable ASLR (do not forget to turn on this protection again, just set value to 2 instead of 0)

sysctl -w kernel.randomize_va_space=0

Or you can use another compiler instead of gcc. For example tcc from tcc:i386 package works good, and clang should work too).
The desired output from crackme looks like:

Checking password...

Login failed!
You found the secret function!
The password is: Rev3ngineering1sc00l!

Here is my input for second solution:

probably you will need to adjust the length of zeros and the address of secret function in this exploit. I compiled crackme with 32-bit tcc compiler.

python -c "print 'A'+'\x00'*55+'\xa2\x82\x04\x08'"  | ./crackme

Thanks for this small puzzle.