缓冲区溢出漏洞浅析(二)

 

 

10月1日整理了缓冲区溢出的C语言例子,今天再整理一下由于程序员编程错误导致的问题。可以理解为常规缓冲区溢出。常规缓冲区溢出是指由于程序员书写错误导致的显式缓冲区溢出漏洞。根据其产生方式,程序行为和调用函数的区别,分成为面几类。

 

  1. 给数组赋值字符串越界

 

缓冲区赋值超过缓冲区长度的字符串常量则会导致缓冲区溢出。

 

 

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

    char cArray[10]="abcdefghijk";

 

    return 0;

 

}

上面例子中,数组长度声明为10,给它赋值的字符串"abcdefghijk"长度为11超过数组本身本身的长度10,导致缓冲区溢出。在数组初始化的时候,一定要注意初始化字符串的长度不要超过给数组合法范围。

 

  1. 数组下标访问越界

数组下标为负数或数组下标超过数组长度的时候,会发生缓冲区溢出。例如

 

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

    char cArray[10];

    cArray[10]=10;

    return 0;

 

}

数组下标值为10,超过数组cArray的长度10,导致发生缓冲区溢出。防止出现问题的方法是对数组下标的取值范围进行判定,即可避免。

 

  1. 初始化内存越界

初始化内存越界是指在对缓冲区空间使用memset初始化的时候,没有考虑到缓冲区的长度,导致初始化长度大于数组长度,发生缓冲区溢出。

 

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

    int iArray[10];

    memset(iArray,0,20);

    return 0;

 

}

  

   数组的长度时10,使用memset初始化内存的长度为20,因此导致缓冲区溢出。

 

  1. 指针操作越界  

 

指针操作越界是指对指针动态分配内存空间后,对指针进行算术运算或者取下标操作,使得操作后的支付指向不合理范围,导致缓冲区溢出。

 

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

    int *p;

    int  *t=20

    p=malloc(sizeof(int)*10);

    p[t]=10;

    *(p+t)=11;

    return 0;

 

}

 

 

上面例子中,声明了指针p,给指针p分配内存空间10,后面对指针进行算术运算导致缓冲区溢出。防止方法是对指针进行算法运算操作之前需要对变量的值范围进行校验,确保指针指向合理的区间范围。

 

  1. 字符串拷贝越界

在使用strcpy等字符串拷贝时,注意src拷贝给des时,如果src长度超过des长度,则会发生溢出。

例如:

 

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

  char a[5];

    char *p="abcdef";

    strcpy(a,p);

    printf("%s",a);

    return 0;

 

}

     当把指针p指向的字符串拷贝到a数组时,6个字符长度超过了数组a长度5,导致发生缓冲区溢出。进行字符串拷贝时,一定要注意来源字符串的长度要小于等于目的缓冲区长度。

 

  1. 格式化字符串导致的缓冲区溢出

 

格式化字符串导致缓冲区溢出是指对字符串格式化时,没有对字符串长度加以限制导致的缓冲区溢出。是一种由越界写数据引起的缓冲区溢出。在使用sprinrf进行格式化字符串时,导致缓冲区溢出。当格式化字符串时,要注意格式化参数长度

  

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

   

  char a[10];

     char *p="3.14159";

     sprintf(a,"p的值为%f",p);

     printf("%s",a);

     return 0;

 

}

 

  上面例子中数组a声明为10个字符长度,但是字符串p长度虽然不足10个字符,但是要添加“"p的值为”字符串,其长度超过10个,所以发生a的缓冲区溢出。

 

 

下面是整理的10种数组越界情况,以及上面的例子可以作为静态代码检测分析工具的进行缓冲区溢出检测检测的Benchmark。

 

例子:下面有10个数组越界情况,在VS 2012上调试通过。

 

array.h头文件

    int i,j;

    int arr[10]={1,2,3,4,5,6,7,8,9,10};

    int arr1[MAX_LEN];

    int arr2[MAX_LEN1];

    int arr3[MAX_GLEN];

ConsoleApplication5.cpp,源文件

#include "stdafx.h"

#include "array.h"

 

#define  MAX_LEN  5

#define  MAX_LEN1  MAX_LEN

#define  SUM(x)  x*x

inline int fun(int x);

 

inline int fun(int x)

{

    return x * x;

}

int _tmain(int argc, _TCHAR* argv[])

{

   

    int  iStatus=0;

    int  num[5];

    int  i=0;

 

    for(int i=0; i<5; i++)

         num[i]=i*2;

 

    i++;

    num[i]=20;

 

    int data=10;

    char *p=NULL;

    scanf_s("%s",p);

    //第一种情况

    for(i=0;i<=10;i++)

    {

        arr[i] = 0;

         printf("%d\n",i);

    }

 

    //第二种情况

    for(i=0;i<10;i++)

    {

        arr[i] = 0;

         printf("%d\n",i);

         j=i;

    }

    ++j;

    printf("arr[%d]=%d\n",j,arr[j]);

  

    //第三种情况

    j=-1;

    arr[j]=-1;

 

    //第四种情况

    for(i=0;i<=5;i++)

    {

         arr1[i]=i;

         printf("%d\n",arr1[i]);

    }

 

    //第五种情况

    for(i=0;i<=5;i++)

    {

         arr2[i]=i;

         printf("%d\n",arr2[i]);

    }

 

    //第六种情况

    for(i=0;i<10;i++)

    {

         arr3[i]=i;

         printf("%d\n",arr3[i]);

    }

    printf("第六种情况循环结束后 i=%d \n",i);

    arr3[i]=10;

    printf("第六种情况循环结束后 arr3[%d]=%d \n",i,arr3[i]);

 

    ++i;

    arr3[i]=11;

    printf("第六种情况arr3[%d]=\n",i,arr3[i]);

 

    //第七种情况

    for(i=0;i<10;i++)

    {

         arr3[i]=i;

         printf("%d\n",arr3[i]);

    }

    int c=SUM(2+3)-1;

    arr3[c]=10;

 

    //第八种情况

    int d=fun(3);

    d++;

    for(i=0;i<10;i++)

    {

         arr3[i]=i;

         printf("%d\n",arr3[i]);

    }

    arr3[d]=10;

 

    //第八种情况

    for(i=10;i>0;i--)

    {

         arr3[i]=i;

         printf("%d\n",arr3[i]);

    }

    i--;

    arr3[i]=0;

    arr3[i--]=-1;

 

    //第九种情况

    i=10;

    while(i>0)

    for(i=10;i>=0;i--)

    {

         arr[i]=i;

         printf("%d\n",arr[i]);

    }

    printf("第9种情况循环结束后 arr[%d]=%d \n",i,arr[i--]);

    arr[i--]=-1;

 

    //第十种情况

    j=10;

    do

    {

       arr[j]=j--;

    }while(j>=0);

    printf("第10种情况循环结束后 arr[%d]=%d \n",--j,arr[j]);

 

        return 0;

}

关注安全  关注作者

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

manok

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值