Return to libc / Ret-to-libc / Ret2libc
Problem Statement:
In cases of buffer overflow based on the standard stack, we simply need to write shellcode into the vulnerable program’s stack and execute it. However, if the program has the NX (non-executable) feature enabled (which is the case with newer systems), we cannot execute shellcode from the program’s stack.
To bypass the protection of NX, today I will introduce the return-to-libc technique, which allows us to bypass the NX bit protection and disrupt the program’s execution flow by reusing existing executable code from the shared standard C library object (libc-*.so), which has been loaded and mapped into the program’s virtual memory space.
The ret-to-libc technique is similar to a regular stack overflow attack, but with one point difference. Instead of overwriting the return address of the vulnerable function with the address of the shellcode during a typical overflow exploit, in the case of ret-to-libc, the return address is overwritten with the memory address pointing to the system(const char *command) function in the libc library. Therefore, when the function is overwritten and returns, the program is forced to jump to the system() function and execute the shell command that has been passed as an argument *command.
In this case, I want the program to spawn a shell /bin/sh, so we will execute the program to reach system(“/bin/sh”).