溢出初步(1)

溢出初步(1) (2006-11-28 07:43:41)
最近学习中安网培提供的缓冲区溢出基础课程,记录了些在进行缓冲区溢出定位学习的体会,与大家分享一下,由于是初学难免有错误,希望各位多多指点。:)

  缓冲区溢出原理:

  就像老师讲的倒啤酒的例子,向一个杯子里灌啤酒,杯子装不下了,啤酒就溢出了。在计算机内存中,当某个数据,超过了处理程序限制的范围时,该数据就会造成程序的执行溢出(overflow)。 

  但计算机是怎样存储数据的,为什么可能造成程序限制的范围呢?进程是如何组织内存中的数据的?

  所以我觉得在掌握缓冲区溢出基础之前,应对内存中数据存储方式有所了解。

  从内存存储分配的角度看,缓冲区就是一段连续分配的内存空间。在程序的函数调用中,缓冲区一般通过堆栈来实现。堆栈是一个后进先出的队列,它的生长方向与内存的生长方向正好相反,正因为这一特点使得溢出攻击可能实现。我通过一个例子谈谈我对堆栈存贮的理解:

  假设程序中有一个函数overflow(buf),当程序调用这个函数时,计算机会将调用此函数的一些地址和参数压入堆栈中,其顺序 为:buf,overflow函数返回地址(以下简称ret),EBP寄存器指向的地址(以下简称EBP),如果函数中有局部变量,接下来会在堆栈中再分 配这些局部变量空间。当函数调用结束时,局部变量空间将被丢弃(但不会清空),然后弹出EBP恢复调用函数前堆栈帧的指向,最后弹出返回地址(ret)到 EIP继续执行下一步主程序。

  总结一下:

  调用函数时堆栈中数据存储为(栈顶->栈底):局部变量->EBP->ret->buf。  

  可以看到,当程序如果使用局部变量时,其长度大于预分配给局部变量空间的时候,多余长度的字符将按照内存存贮方向填充,而前面提到堆栈的生长方向与内 存生长方向相反,于是EBP,ret就可能被多余的字符所覆盖,在函数返回时ret已不是原来的值,而是一个错误的值,这个值被弹入EIP后,cpu可不 管它是不是原来的地址,就照EIP指向的地址去执行程序,可想而知这个错误地址指向的内存地方不是正确的主程序下一步语句,错误也就出现了,就是所说的溢 出了,呵呵。  

  如果我们精心设计一个这种多余的字符,使得它所覆盖的ret地址能够指向我们自己编写的shellcode并加以执行,也就达到了我们利用缓冲区溢出漏洞的目的。  

  了解了溢出产生的原因,当我们遇到存在这种漏洞的程序并打算加以利用时,就要准确确定这个溢出点,也就是需要填充多少字符刚好能够覆盖我们需要的ret。

  由于水平有限,还不足以分析存在缓冲区漏洞的较大程序(惭愧,惭愧),因此参考教学视频写了一个模拟的小例子,练习一下中安网培课程中介绍的利用报错对话框来确定溢出点的方法。

  第一步:

  test1.c

  #include

  #include

  int overflow(char *buf)

  {

   char output[8];

   strcpy(output,buf);

   printf("buf的地址是:%p/n",buf);

   printf("output内容为:%s/n",output);

   return 0;

  }

  int main()

  {

   char buf[26];

   for(int j=0;j<26;j++)

   {

   buf[j]='A';

   }

   overflow(buf);

   return 0;

  }
 
 
 


http://xiaonei.com/getuser.do?id=56454345

i am cricket  

有人说我签名太长了。那我写成字算了,就不长了。
是不是?
cricket  白羊座 子鼠

美女,在线



头衔:我想你你知道吗
职务:论坛版主
级别:精灵使
魅力:14
金币:9369
经验:95559
文章:9299
注册:03-10-23 11:25
发表: 2006-11-24 22:28:00 8

缓冲区溢出
审查代码是否存在缓冲区溢出时,将审查工作主要放在通过 P/Invoke 或者 COM 互操作层调用非托管代码的代码上。托管代码本身受到缓冲区溢出攻击的可能性很小,因为无论是否访问数组,系统都将自动检查数组边界。只要您调用了 Win32 DLL 或者 COM 对象,都应该严格检查 API 调用。

以下过程有助于定位缓冲区溢出缺陷:

1.
 定位对非托管代码的调用。

扫描源文件中的“System.Runtime.InteropServices”,这是调用非托管代码时使用的命名空间名称。
 
2.
 检查传给非托管 API 的字符串参数。

这些参数是缓冲区溢出的主要来源。检查您的代码,检查所有输入字符串的长度,验证它是否没有超过 API 定义的限制。如果非托管 API 接受字符指针,您可能无法知道最大允许字符串长度,除非有非托管源代码的访问权限。常见缺陷如以下代码片段所示:

void SomeFunction( char *pszInput )
{
  char szBuffer[10];
  // Look out, no length checks. Input is copied straight into the buffer
  // Should check length or use strncpy.
  strcpy(szBuffer, pszInput);
  . . .
}
 

注 如果您使用 strncpy,缓冲区溢出仍然可能发生,因为它不检查目标字符串中是否有足够空间,只限制复制字符的数量。

如果您因为并不拥有非托管代码而无法检查它,那么就通过故意传入长的输入字符串和无效参数严格测试 API。
 
3.
 检查文件路径长度。

如果非托管 API 接受文件名和路径,那么应该检查您的包装方法,检查文件名和路径是否没有超过 260 个字符。这是通过 Win32 MAX_PATH 常数定义的。还应该注意目录名和注册表项可能的最大字符数是 248。
 
4.
 检查输出字符串。

检查是否代码使用了 StringBuilder 接收从非托管 API 传回的字符串。检查 StringBuilder 的容量是否足够大,可容纳非托管 API 传回的最长字符串,因为非托管代码传回的字符串可能是任意长度的。
 
5.
 检查数组边界。

如果您使用数组将输入传递到非托管 API,应该检查托管包装,验证是否没有超过数组容量。
 
6.
 检查您的非托管代码是否用 /GS 开关进行编译。

如果您拥有非托管代码,使用 /GS 开关启用堆栈探测,检测是否存在某些类型的缓冲区溢出。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值