您的代码是否能够抵御缓冲区溢出漏洞的威胁?

缓冲区溢出已经困扰C/ c++开发社区很多年了。虽然C语言允许开发人员通过指针直接访问内存,但它也为溢出问题打开了大门。安全编码实践可以帮助开发人员在某种程度上避免缓冲区溢出(以性能为代价),但有时缓冲区溢出可能很微妙,很难发现和解决。

通常,只有当缓冲区溢出逃到生产环境中,并被发现是一个安全漏洞(或者更糟,被利用)时,人们才会意识到它是如何巧妙地引入到代码中的。还记得Heartbleed错误在流行的OpenSSL库中?最近的Cloudbleed错误或者是Heartbleed解释为这个问题提供好的例子。

什么是缓冲区溢出?

一般来说,当向已分配的缓冲区写入数据的操作超出缓冲区边界时,就会发生缓冲区溢出。在此过程中,操作访问了不应该访问的相邻内存位置。让我们来看一个例子:

#定义MAXSIZE 100。char localBuf [MAXSIZE] . .得到(localBuf)

得到()函数不允许您检查数据是否读到localBuf小于最大尺寸字符。您依赖于数据的发送方保持在这个限制之内。恶意用户通过发送大于的数据很容易溢出缓冲区最大尺寸字符并访问堆栈中的相邻区域。

显示分配给本地包的存储空间和可被溢出的本地包访问的区域的图表

显示分配给本地包的存储空间和可被溢出的本地包访问的区域的图表。

缓冲区溢出有多严重?

缓冲区溢出的严重程度取决于相邻内存区域中存储的内容。在代码中调用函数时,与该调用相关的所有数据都存储在调用堆栈的相邻区域中。

考虑以下两种情况:

  • 与溢出缓冲区相邻的区域存储另一个局部变量或函数参数
    由于缓冲区溢出,变量值已损坏。您可能会在代码的其他地方遇到导致运行时错误的损坏值。损坏的值还可能导致无声的不正确行为——可以逃避检测。你最终得到的是不安全且不可靠的代码。
  • 与溢出缓冲区相邻的区域存储函数的返回地址
    调用堆栈还存储被调用函数返回时程序跳转到的地址。由于缓冲区溢出,该地址已被破坏。攻击者可以精确地溢出缓冲区,使程序不会返回调用站点,而是跳转到恶意代码所在的位置。如果您的程序具有足够的特权,则恶意代码可以控制您的应用程序并导致被利用。

避免缓冲区溢出有多难?

你可能会说上面所示的问题很容易避免。在使用不安全的函数之前,如得到(),检查缓冲区大小。或者,更好的是,根本不使用这种不安全的函数。

考虑另一个缓冲区溢出的例子,看看它有多微妙。此代码片段来自libPNG图像解码器,被多个应用程序使用,包括Mozilla和一些版本的Internet Explorer (cf。OWASP).

如果(!(png_ptr->模式& PNG_HAVE_PLTE)){/*应该是一个错误,但我们可以处理它*/ png_warning(png_ptr,“tRNS之前缺少PLTE”);} else if(长度> (png_uint_32)png_ptr->num_palette) {png_warning(png_ptr,“错误的tRNS块长度”);png_crc_finish (png_ptr、长度);返回;}……Png_crc_read (png_ptr, readbuf, (png_size_t)length);

乍一看,检查如下:

长度> (png_uint_32)png_ptr->num_palette

正是使用length时避免缓冲区溢出所需要的。然而,这里的障碍是检查发生在其他的如果块。的如果块前面的其他的如果块执行不相关的检查png_ptr - >模式;如果之前的检查失败,控制将超出If - else If链与只是一个警告。对可变长度的第二次检查根本没有执行。

换句话说,存在一个执行路径子集,尽管进行了检查,但仍可能发生缓冲区溢出。只有当您能够跟踪程序中的所有执行路径时,才能检测到如此微妙的问题。这正是Polyspace静态分析所做的。

如何使用Polyspace静态分析来避免缓冲区溢出?

有大量的静态分析工具声称可以检查缓冲区溢出,它们使用不同的启发式或某种形式的数据流分析来执行此操作。然而,这是一种不够充分的方法,因为对安全和安全性至关重要的系统不能在部署的嵌入式软件中出现任何假阴性(即,错过缓冲区溢出的实例)。

Polyspace®下载188bet金宝搏产品采用两步方法来应对这一挑战。这种方法与软件开发工作流程的需求是一致的。

Polyspace Bug Finder™应用快速形式化方法,使开发人员能够遵守编码准则,这有助于避免缓冲区溢出。Polyspace Bug Finder提供了各种检查程序,不仅可以识别缓冲区溢出问题,还可以识别其他可能导致和利用缓冲区溢出漏洞的潜在结构。这种早期快速的反馈使开发团队能够在这些问题进一步传播到软件构建之前解决这些问题,从而节省测试和调试资源。

例如,如果您遵循CWE或CERT C等安全标准,则可以使用Polyspace Bug Finder来遵守规则。以下CWE id、CERT C规则和ISO 17961安全编码指南处理缓冲区溢出:

  • CWE
    • CWE 121:基于栈的缓冲区溢出
    • CWE 129:数组索引验证不当
  • CERT C
    • INT04-C:强制限制来自污染源的整数值
    • ARR30-C:不要形成或使用越界指针或数组下标
  • ISO / IEC 17961
    • invptr:形成或使用越界指针或数组下标
    • taintformatio:使用受污染的值使用格式化的输入或输出函数写入对象

MISRA C:2012指令4.14规定,“应检查从外部来源接收的值的有效性。”

Polyspace Bug Finder,通过它各种检查,为检测和避免基于堆栈的缓冲区溢出提供了广金宝app泛的支持。

  • 数组访问越界:可以使用索引来超出数组的大小。
    int我;int fib [10];For (i = 0;I < 10;if (I < 2) fib[I] = 1;Else fib[i] = fib[i-1] + fib[i-2];} printf("第10个斐波那契数是%i .\n", fib[i]);
  • 指针访问越界:您可以使用分配给内存块的指针来访问该块以外的内存。
    int arr [10];int * ptr = arr;For (int i=0;I <=9;i++) {ptr++;* ptr =我;/* i=9 */}: ptr out of bounds
  • 索引受污染的数组访问:可以从外部获取变量作为数组的索引,而不需要检查变量的值是否小于数组的大小。
    #定义MAXSIZE 100int arr(最大尺寸);int func(int num) {int localVar;/*没有检查num的临时代码*/加勒比海盗(num) = localVar;
  • 字符串操作中的目标缓冲区溢出:您可以使用字符串操作函数,例如sprintf ()并且写入的字符串对于写入的缓冲区来说太大了。
    字符缓冲区[20];char *fmt_string = "这是一个很长的字符串,它不适合在缓冲区";sprintf(缓冲区,fmt_string);
  • 错误的字符串格式说明符导致缓冲区溢出:当你使用函数,如sscanf,则字符串格式说明符指示字符串大小大于为该字符串分配的存储区域。
    char buf [32];Sscanf (str[1], "%33c", buf);

尽管有Polyspace Bug Finder的分析,一些微妙而复杂的缓冲区溢出缺陷可能仍然存在于源代码中,因为Polyspace Bug Finder不是一个健全的工具(也就是说,它可能有假阴性)。这就是Polyspace Code Prover™可以提供帮助的地方,因为它是一个基于抽象解释的形式化语义分析工具,可以详尽地验证动态运行时行为。

如何使用Polyspace代码验证程序来避免缓冲区溢出?

在前面的示例中,尽管对长度进行了检查,但缓冲区溢出可能会通过一个控制路径悄悄地潜入。当这些路径依赖于运行时信息时,您将遇到更复杂的情况。

Polyspace Code Prover精确地执行这个功能。Polyspace Code验证程序运行时检查,数组索引出界而且非法解除引用的指针,在程序中所有输入组合和其他变量的所有执行路径上寻找潜在的缓冲区溢出。这意味着在前面讨论的例子中:

如果(!(png_ptr->模式& PNG_HAVE_PLTE)){/*应该是一个错误,但我们可以处理它*/ png_warning(png_ptr,“tRNS之前缺少PLTE”);} else if(长度> (png_uint_32)png_ptr->num_palette) {png_warning(png_ptr,“错误的tRNS块长度”);png_crc_finish (png_ptr、长度);返回;}……Png_crc_read (png_ptr, readbuf, (png_size_t)length);

Polyspace Code Prover可以识别变量长度不是沿着所有路径有界的。相应的Polyspace Bug Finder检查器,数组访问越界而且指针访问越界,也要注意这类问题。当发现至少一个导致溢出的控制路径时,它们会报告。然而,这些检查器并不执行详尽的分析。您必须使用代码验证工具,如Polyspace code Prover,并确保所有指针访问都是绿色的,因此永远不会证明会导致缓冲区溢出。

在代码审查和单元测试之前,这种详细的分析是理想的,因为您可以根据Polyspace code Prover提供的运行时数据减少和优化您的测试用例。因此,同时使用Polyspace Bug Finder和Polyspace Code provver,可以确保缓冲区溢出的恶性威胁的安全性。

其他真实世界的例子