f()被调用时,堆栈将象这样: 
    
        
            
            
            |_______$1_______| EBP+16
|_______$2_______| EBP+12
|_______$3_______| EBP+8
|_return address_| EBP+4
|___saved_ESP____| EBP           ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo2______| EBP-12
|______foo2______| EBP-16
|______foo2______| EBP-20 
             
             | 
         
    
 
  你可以相信,当我们对f001装载超过8个字节对和对foo2超过12个字节,我们将溢出他们的空间。如果你对foo1写入超过4个字节,你将重写被保护的EBP,而且……如果你写入超过4个字节,你将重写返回地址……而这不正是我们都想要的吗?这是内存溢出的基础……让我设法用一段简单的代码稍微阐明一下这种现象,假设我们有这样的代码:  
    
        
            
            
            c.c :
#include <string.h>
void f(char *str)
{
        char foo[16];
        strcpy(foo, str);
}
void main()
{
        char large_one[256];
        memset(large_one, 'A', 255);
        f(large_one);
}
[murat@victim murat]$ make c
cc -W -Wall -pedantic -g    c.c   -o c
[murat@victim murat]$ ./c
Segmentation fault (core dumped)
[murat@victim murat]$ 
             
             | 
         
    
 
  我们在上面做的是简单的写255字节到一个只能容纳16字节的数组里。我们传递了一个256字节的大数组作为一个参数给f()函数。在函数内部,没有边界检测我们拷贝了整个large_one到foo,溢出了foo和其它数据。因此缓冲区被填写了,同样的strcpy()用A填写了内存的其它部分,包括返回地址。  
  这里是用gdb生成核文件代码的检查:  
    
        
            
            
            [murat@victim murat]$ gdb -q c core
Core was generated by `./c'.
Program terminated with signal 11, Segmentation fault.
find_solib: Can't read pathname for load map: Input/output error
#0  0x41414141 in ?? ()
(gdb) 
             
             | 
         
    
 
  可以看出,CPU在EIP中看到0x41414141(041是字母A的十六进制ASCII 码),试图存储和执行此处的指令。然而,0x41414141不是我们的程序被允许存储的内存地址。最后操作系统发了一个SIGSEGV (Segmentation Violation)段侵犯信号给程序并且停止了任何进一步的操作。  
  我们调用f()时,堆栈看起来象这样:  
    
        
            
            
            |______*str______| EBP+8
|_return address_| EBP+4
|___saved_ESP____| EBP           ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo1______| EBP-12
|______foo1______| EBP-16 
             
             | 
         
    
 
  strcpy()从foo1的开头,EBP-16开始,拷贝large_one到foo,没有边界检查,用A填充了整个堆栈。  
  现在我们能够重写返回地址,如果我们放一些其它的内存段地址,我们能在那里执行指令码?答案是肯定的。假如我们放了一些 /bin/sh spawn出的指令在一些内存地址中,而我们把这个地址放到我们溢出的这个函数返回地址中,我们就能spawn出一个shell,而且很有可能,既然你已经对setuid二进制程序感兴趣了,我们将spawn出一个root shell。  
  (待续) 
  黑客经典教程之缓冲区溢出解密(一) 
-- 原文作者: Murat 原文链接: http://www.enderunix.org/documents/eng/bof-eng.txt  引用链接: http://industry.ccidnet.com/art/1101/20060911/897057_1.html 
		      
		      
		      
		      
		      
		      
                      
		      
		        
		      共3页: 上一页 [1] [2] 3 下一页 
		     |