`

c/c++ 缓冲区溢出

阅读更多

在 C 和 C++ 中,缓冲区通常是使用数组和诸如 malloc() new 这样的内存分配例程来实现的。极其常见的缓冲区种类是简单的字符数组。溢出是指数据被添加到分配给该缓冲区的内存块之外。

 

在几乎所有计算机语言中,不管是新的语言还是旧的语言,使缓冲区溢出的任何尝试通常都会被该语言本身自动检测并阻止(比如通过引发一个异常或根据需要给缓冲区添加更多空间)。但是有两种语言不是这样:C 和 C++ 语言。C 和 C++ 语言通常只是让额外的数据乱写到其余内存的任何位置,而这种情况可能被利用从而导致恐怖的结果。更糟糕的是,用 C 和 C++ 编写正确的代码来始终如一地处理缓冲区溢出则更为困难;很容易就会意外地导致缓冲区溢出。除了 C 和 C++ 使用得非常广泛外,上述这些可能都是不相关的事实;例如,Red Hat Linux 7.1 中 86% 的代码行都是用 C 或 C ++ 编写的。因此,大量的代码对这个问题都是脆弱的,因为实现语言无法保护代码避免这个问题。

 

C 和 C++ 附带的大量危险函数或普遍使用的库甚至连检查空间也无法做到。程序对这些函数的任何使用都是一个警告信号,因为除非慎重地使用它们,否则它们就会成为程序缺陷。您不需要记住这些函数的列表;我的真正目的是说明这个问题是多么普遍。这些函数包括 strcpy(3)、strcat(3)、sprintf(3) (及其同类 vsprintf(3) )和 gets(3)scanf() 函数集( scanf(3)、fscanf(3)、sscanf(3)、vscanf(3)、vsscanf(3)vfscanf(3) )可能会导致问题,因为使用一个没有定义最大长度的格式是很容易的(当读取不受信任的输入时,使用格式“%s”总是一个错误)。

其他危险的函数包括 realpath(3)、getopt(3)、getpass(3)、streadd(3)、strecpy(3)strtrns(3) 。 从理论上讲, snprintf() 应该是相对安全的 ―― 在现代 GNU/Linux 系统中的确是这样。但是非常老的 UNIX 和 Linux 系统没有实现 snprintf() 所应该实现的保护机制。

 

Microsoft 的库中还有在相应平台上导致同类问题的其他函数(这些函数包括 wcscpy()、_tcscpy()、_mbscpy()、wcscat()、_tcscat()、_mbscat()CopyMemory() )。注意,如果使用 Microsoft 的 MultiByteToWideChar() 函数,还存在一个常见的危险错误 ―― 该函数需要一个最大尺寸作为字符数目,但是程序员经常将该尺寸以字节计(更普遍的需要),结果导致缓冲区溢出缺陷。

另一个问题是 C 和 C++ 对整数具有非常弱的类型检查,一般不会检测操作这些整数的问题。由于它们要求程序员手工做所有的问题检测工作,因此以某种可被利用的方式不正确地操作那些整数是很容易的。特别是,当您需要跟踪缓冲区长度或读取某个内容的长度时,通常就是这种情况。但是如果使用一个有符号的值来存储这个长度值会发生什么情况呢 ―― 攻击者会使它“成为负值”,然后把该数据解释为一个实际上很大的正值吗?当数字值在不同的尺寸之间转换时,攻击者会利用这个操作吗?数值溢出可被利用吗? 有时处理整数的方式会导致程序缺陷。

 

针对缓冲区溢出的一种简单解决办法就是转为使用能够防止缓冲区溢出的语言。毕竟,除了 C 和 C++ 外,几乎每种高级语言都具有有效防止缓冲区溢出的内置机制。

 

防止使用在处理字符串时不检查buffer边界的函数,如gets()strcpy()strcat()sprintf()fscanf()scanf()vsprin tf()realpath()getopt()getpass()streadd()strecpy()strtrns(),同样,避免使用execlp()execvp()。永远不要用system()popen()系统调用;

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics