This time we have a Reverse Code Engineering challenge . This challenge is really useful for beginners who like to jump head-first into RCE.
Challenge info: (link to challenge)
.
The file provided is called "basic_re", and has no extension. Lets check in a text editor or hex editor to see if it has a magic number in its header. It does..
For confirmation, we could run TRiD on it:
So it's an ELF file. How to approach it?
We should run it on our Linux VM to see what it does, then we could disassemble it (and debug it if needed) using IDA free or Radare2, GDB, or any tool. Lets go..
.
I'll try Radare2 first. Load the file first into radare2..
Then we'll continue with the help of this wonderful radare cheat-sheet.
Lets analyze functions, then list the names of all of them..
We've got a "main( )" function.. Lets check it out in the graph mode..
We seek to it first (notice the change of the address on the left), and then use "VV" command.
This is what we get...
If you look closely, you'll see parts of the flag up there. (inserted as comments by Radare2)
So basically we got the flag. But our goal here is to learn more, not just to pass this challenge. So here is a quick explanation:
The Orange box:
- Runs "printf" function with some string as an argument. This string is "Do You Want to Play" .
Yellow box:
- Copies the address of local buffer (local_40h) into argument 2.
- Copies the address of the format string (%s%) into argument 1.
- Runs "scanf" function with arguments 1 and 2 to take our input.
Red box:
- Runs "printf" function with some string as an argument. This string is "No You are evil Get out"
Then we exit the main( ) function using Leave and Ret instructions.
.
So there is no control flow here. Meaning that our input doesnt influence the behaviour of this applications. But the flag is stored in this function's local variables (local_20h, local_18h and local_10h) which is on the function's stack.
_____
To understand the concept of local variables better, lets pop up GDB and inspect the local variables on the stack with our own eyes.
Lets run it once using "run" command, then type anything when it asks for input. The process will then terminate successfully. (the red box)
Lets disassemble the main function : disassemble main. (the yellow box).
The code looks a bit strange because this is AT&T's assembly syntax. We could tell GDB to use the Intel's assembly syntax, but we wont need to do that here.
Our plan now:
- Put a breakpoint right after the program stores the flag in the local variables on the stack (local_20h, local_18h and local_10h)
- Run the program, it will stop at the breakpoint
- Inspect the stack, to see if the flag is really there
1- Breakpoint
We should insert the breakpoint at address "0x00005555555546dc" which is right after the 3rd command (3rd red line in the image above) that copies the flag into our local variable.
2- Lets run it. It hits the breakpoint
Check the registers, we want to see the value of RSP (Stack Pointer, which points to the top of the stack). This step is not required, but it shows how to check registers' value ?
3- Lets examine the values at the top of the stack (using the command x). I'll use the command "x/30g" to examine 30 values at the top of the stack, each value is "g" (Giant words) because this is a 64-bit binary. (we would use x/30w if it were a 32-bit binary).
Anything familiar? Probably not..
How about we ask GDB to print those values as Strings?
We do that using "x/30s" instead of "x/30g"
That's our flag right there..
Pretty cool, right?
.
Now the steps you should try by yourself..
- Continue execution of the program line by line in GDB (using "next" or "step" commands) after the breakpoint, till you hit the return and exit out of the main function.
- Inspect the stack.
- You wont find the flag there. Why? because the flag was in the function's local variables.. and the stack gets cleaned after the functions returns