Hello,

In this article I present you the solution to nice and short cracking challenge from Root-Me. After opening it up in Ghidra, I saw that the challenge is easy to solve, all you need is to find the password, which is in plain text. Basically just copy paste and you get the flag, but wait, there’s a twist!

I should have learned my lesson from the other challenge from Root-Me, which also had a twist.

I feel ashamed that I didn’t observe this, just like the password everything was in plain sight 🙁

See what I mean?

function_ptr.2175 is a pointer to a function and in the program’s main it is made to point to the auth‘s address, then it’s called.

    0804869e b8 f4 86        MOV        dest,auth
             04 08
    080486a3 a3 f4 a0        MOV        [function_ptr.2175],dest                         = 00000000
             04 08

And, if we inspect the auth function, we can see that it calls the _asm_ function if the password we provided matches.

cmp_ret = strcmp(buff,dest);<br></br>   if (cmp_ret == 0) {<br></br>     _asm_();<br></br>   }

We can input the right password and get the flag, that’s what I did at first, or, we can do a simple buffer overflow exploit in order to force the program call the _asm_ function directly.

The function pointer and the buffer are located in the .bss section of the binary. the .bss section contains uninitialized objects, in our case the global and static variables.

Somehow, the compiler decided to place the function pointer right after the buffer, the buffer on which the following piece of code gets executed:

strcpy(buffer.2176,argv[1]);

The buffer is only 146 bytes wide and at 146+2 starts the function pointer, this means that we can control what’s written in the function pointer if we can overflow the buffer.

We can do that, because, strcpy continues to copy values into the buffer unless a NULL terminating character is reached.

What we need to know now, is the address of the _asm_ function. Which can be easily found. Either look at the dissembler view or use the nm tool.

➜  /vagrant nm Exploit_Me(if_you_can)<br></br> 08048731 T <em>asm</em>

If we construct a payload that outputs ‘x’ 148 times to overflow the buffer and then append the _asm_’s address to it we successfully exploit the binary:

➜  /vagrant ./Exploit_Me(if_you_can) $(python -c "print('x'*148+'\x31\x87\x04\x08')")<br></br> [+] Felicitation password de validation de l'épreuve:: <redacted>
  • $() – spawns a new shell
  • python -c “..” parses the program as a string

The ./Exploit_Me(if_you_can) binary will get the output as the first argument and that’s it! The buffer overflows, the function pointer gets overridden and the program executes _asm_ instead of auth.

function_ptr.2175 = auth; # Had this been after the strcpy things would have been different.<br></br>strcpy(buffer.2176,argv[1]);<br></br>*(undefined *)((int)dest + 8) = '_';<br></br>*(undefined *)((int)dest + 9) = '.';<br></br>iVar1 = (*(code *)function_ptr.2175)(buffer.2176,dest);

In case you’re wondering why is the asm address written as ‘\x31\x87\x04\x08’, it is because we want it in little-endian format. In big endian the address is 0x08048731.

The _asm_ function is quite complicated, it decrypts the flag, the magic here is that it doesn’t depend on the program state or any arguments, thus if we manage to execute it we get the flag directly.

You can also solve this challenge in other ways, check the solutions on Root-Me for more creative ways in solving this crackme.

Thank you for reading!