ELF x86 — Stack buffer overflow basic 6 Rootme (App-System) (Introduction to Ret2libc)

Hariharan@Blog:~$
5 min readJul 24, 2021

--

Let me be honest with you, I was thinking ret2libc and Return oriented programming is a tough concept. But it turns out to be easy. I will be giving some basic introduction to Ret2libc (Return to Libc) before starting with the challenge. Feel free to skip the introduction part if you are familiar with Ret2libc.

Introduction to Ret2libc

First, we have to know about the Non-Executable Stack.

Non-executable stack (NX) is a virtual memory protection mechanism to block shell code injection from executing on the stack by restricting a particular memory and implementing the NX bit.

This is a type of memory protection mechanism. You cannot do a normal buffer overflow here. We have been doing buffer overflow to execute a shell and get the flag. But if you see in challenge 6, we don’t have a shell function or a system call. We need to execute it ourselves by injecting a particular payload that can pop a shell.

In this case, we use Ret2libc. But so far I was talking only about this challenge. As I said earlier, if you have a Non-Executable Stack, this method might come in handy.

There is a library called Libc. Libc is a standard library for the C programming language. This contains various function like system() calls, strcpy() , exit() and so on. The basic ideology is to recreate the system call to a shell, which we have been seeing in previous Rootme challenges. But how?

We need to locate the Libc and system() in the virtual memory after executing the program. Then find “/bin/bash” or “/bin/sh” which again will be located in the virtual memory. Accessing this library doesn’t have any connection with the memory protection (Non-Executable Stack). Then we execute a command like a system(“/bin/sh”) to execute a shell.

Finding the system() inside Libc and “/bin/sh” is the next task. As usual, we just use gdb. Create a break-point at the main. Then execute

p system

You’ll get the address for the system. Then we need to search for “/bin/sh” or “/bin/bash” which we need to use the proc map. It would be better to show this directly in the challenge.

Don’t worry if you didn’t understand the above explanation. It will be much easier to relate when we do the challenge.

Challenge

We will see the source code for the following challenge.

Let us try to analyze the code. We have a variable “message” of type char and has a size of 20 bytes. This means it can hold 20 characters. We directly skip to setreuid(), as the function above doesn’t make any sense now. Then we see the strcpy(). It takes in the argument argv. Clearly, we need to give our input in the command line. Then it prints out the message. Strcpy() doesn’t care about the size of argv. The first 20 bytes will be assigned to the variable “message”. So this is our place of attack as we can overflow and overwrite EIP.

First, we need to know the size of buffer and padding along with EBP to write our exploit. For this, use GDB and disassemble main. I am not pasting the entire code here as it is too long.

If you analyze the code, clearly ebp-0x1c is used before strcpy(). If you have read my previous blogs, you’ll know why I am taking note of this. We know the variable “message” has a size of 20 bytes. Then EBP should be 4 bytes. So we need to find the padding size with the usual calculation. As usual, I am going to draw the stack diagram.

With calculation, we can see the padding used here is 8 bytes. This can be directly obtained from starting of the code. But I like to use this method. Now we find where the system() and “/bin/sh” are located in the virtual memory.

Now we have the address for the system(). Next, we need to see where “/bin/sh” is located. For this, we use the command “info proc map”. We note down the address of where Libc starts and where it ends.

Now we can use a command called find . The syntax is as follows.

find *starting_address* , *ending_address* , “string”

So we have the address for “/bin/sh” too .

Now we are ready to write our exploit. Basic methodology, First overflow the buffer with 32 bytes of a random character. Then place the system() address in little-endian format at EIP/Return Address. Now fill with 4 bytes of random character again and finally our address “/bin/sh” in little-endian format.

But as already mentioned, we need to give this exploit as an argument. We use a $ symbol for this. And there we go! we found our flag!

Hope you understood Ret2libc. I know it will be hard to understand at first, but try to do the challenge on your own. Also, draw a stack diagram like me. This will help you in the calculation.

Do give some claps if you reached here :). And feel free to ask your doubts in the comment section. It would help others too!

Goodbye :)

--

--

Hariharan@Blog:~$
Hariharan@Blog:~$

No responses yet