(转载翻译)缓冲区溢出攻击是如何运行的

nicky   ·   发表于 2020-04-12 10:38:18   ·   技术文章投稿区

当程序尝试用比缓冲区极限容纳的更多的数据填充内存块(内存缓冲区)时,就会发生缓冲区溢出。举一个例子,把水比作数据,把杯子当成内存缓冲区,如果水太多了就会溢出来这个道理。

通过将修改好的用户输入发送给易受攻击的应用程序,攻击者可以迫使应用程序执行任意代码来控制计算机或使系统崩溃。 缓冲区溢出漏洞是由程序员的错误引起的,这些错误很容易理解,但更难避免和防范。

什么会导致缓冲区溢出

缓冲区溢出漏洞(也称为缓冲区溢出)的想法很简单。 以下是具有缓冲区溢出漏洞的C程序的源代码:

当我们编译并运行此漏洞程序时,您认为会发生什么? 答案是任何事情都可能发生。 执行此代码段时,它将尝试将15个字节放入只有5个字节长的目标缓冲区中。

这意味着会有十个字节写入阵列外部的内存地址。 以后发生的情况取决于被覆盖的十个字节的内存的原始内容。 也许重要的变量存储在这里,而我们刚刚更改了它们的值?

上面的例子以明显的方式被破坏。 因此,让我们考虑另一个示例。 假设我们需要从文件中读取IP地址。 我们可以使用以下C代码来做到这一点:

上面例子中的错误可能并不明显。 我们假设要从文件中读取的IP地址不会超过15个字节。 正确的IP地址(例如255.255.255.255)是不能超过15个字节。 但是,恶意用户可以准备一个包含非常长的伪字符串而不是IP地址的文件(例如19222222222.16888888.0.1)。 该字符串将导致我们的程序溢出目标缓冲区。

堆栈缓冲区溢出攻击示例

既然我们已经知道程序会溢出数组并覆盖不应该覆盖的内存片段,那么让我们来看看如何将其用于发起缓冲区溢出攻击。 在典型情况下,该问题是由于将数据与控制程序执行的命令混合在一起而引起的,就像许多信息安全问题一样。

与大多数编程语言一样,在C语言中,程序是使用函数构建的。 函数会相互调用,彼此传递参数,然后返回值。 比如上面的例子中,我们的代码从文件中读取IP地址,这可能是称为readIpAddress的函数的一部分,该函数从文件中读取IP地址并进行解析。

该功能可以由其他一些功能调用,例如readConfiguration。 当readConfiguration调用readIpAddress时,它将传递一个文件名,然后readIpAddress函数将IP地址作为四个字节的数组返回。

在此函数调用期间,三种不同的信息并排存储在计算机内存中。 对于每个程序,操作系统维护一个内存区域,其中包括一个称为堆栈或调用堆栈的部分。 调用函数时,会将堆栈的一部分分配给它。 这部分堆栈会用于:

记住函数执行完成后应从中重新开始执行的代码行(在我们的示例中,为readConfiguration函数中的特定行):

1.存储由其调用者传递给函数的参数(在示例中就是,/ home / someuser / myconfiguration / ip.txt)
2.将函数返回的返回值存储到其调用方(例如(192,168,0,1))
3.在执行此函数时存储被调用函数的局部变量(在示例中,为变量char [MAX_IP_LENGTH] buf)

因此,如果程序在堆栈中分配了一个缓冲区,并试图在其中放置太多的数据,则用户输入的数据可能会溢出并覆盖存储返回地址的内存位置。

如果问题是由用户不小心输错数据引起的,则新返回地址很可能不会指向存储任何其他程序的存储位置,因此原始程序将完全崩溃。 但是,如果精心准备了数据,则可能导致不必要的代码执行。

攻击者第一步是准备可执行代码并为攻击者的利益工作的数据。 第二步是将该恶意数据的地址放置在返回地址应位于的确切位置。

实际上,当函数读取IP字符串并将其放入目标缓冲区时,返回地址将替换为恶意代码的地址。 函数结束后,程序执行将跳至恶意代码。

缓冲区溢出和WEB

但是,即使使用高级语言的程序员也应该了解并关心缓冲区溢出攻击。 他们的程序通常在用C编写的操作系统中执行,或者使用用C编写的运行时环境,并且此C代码可能容易受到此类攻击。

为了解缓冲区溢出漏洞如何影响使用这种高级编程语言的程序员,分析一下CVE-2015-3329 –一个真实的安全漏洞,该漏洞在2015年的PHP标准库中被发现。

一个PHP应用程序是* .php。 为了简化分发此类应用程序的过程,可以将其打包为单个文件存档zip文件,tar文件或使用称为phar的自定义PHP格式。

一个名为phar的PHP扩展包含一个类,您可以使用该类来处理此类归档文件。 使用此类,可以解析,列出文档,提取文件等。使用此类非常简单,例如,要从文档中提取所有文件,可以使用以下代码:

当Phar类解析存档时,它将读取存档中的所有文件名,将每个文件名与存档文件名连接起来,然后计算校验和。 比如,对于一个名为myarchive.phar的包含文件index.php和components / hello.php的档案,Phar类计算两个字符串的校验和:myarchive.pharindex.php和myarchive.pharcomponents / hello.php。

作者以这种方式实现它的原因在这里并不重要,重要的是他们如何实现它。 直到2015年,此操作都是使用以下函数完成的:

如我们所见,此函数创建了一个称为tmp的字符数组。 首先,使用以下命令将phar归档文件的名称复制到此数组中:

在此命令中:

第一个参数tmp是应复制字节的目标位置。
第二个参数entry-> phar-> fname是从中复制字节的源,在本例中为归档文件的文件名(myarchive.phar)。
第三个参数entry-> phar-> fname_len是应复制的字节数–在我们的例子中,它是归档文件名的长度

该函数使用以下命令将文件名复制到tmp char数组中:

在此命令中:

第一个参数tmp + entry-> phar-> fname_len是应该复制字节的目标位置–在我们的示例中,它是tmp数组中存档文件名末尾的位置。
第二个参数entry-> filename是从中复制字节的源。
第三个参数entry-> filename_len是应复制的字节数。

然后,调用zend_get_hash_value函数以计算哈希码。

请注意如何声明缓冲区的大小:

它的大小为MAXPATHLEN,是一个常量,定义为当前平台上文件系统路径的最大长度。

作者假设,如果将归档文件的文件名与归档文件内的文件名连接在一起,则它们将永远不会超过允许的最大路径长度。 在正常情况下,可以满足此假设。 但是,如果攻击者准备了一个文件名过长的归档文件,则缓冲区溢出即将来临。 函数phar_set_inode将导致tmp数组中的溢出。

攻击者可以使用它来破坏PHP(导致拒绝服务),甚至使其执行恶意代码。 问题类似于我们的简单示例–程序员犯了一个简单的错误,过于信任用户输入,并假定数据始终适合固定大小的缓冲区。 不过此漏洞于2015年被发现并修复。

转载:
https://www.netsparker.com/blog/web-security/buffer-overflow-attacks/

用户名金币积分时间理由
奖励系统 100.00 0 2020-07-26 11:11:26 投稿满 10 赞奖励
奖励系统 50.00 0 2020-06-20 19:07:29 投稿满 5 赞奖励

打赏我,让我更有动力~

0 Reply   |  Until 2020-4-12 | 676 View
LoginCan Publish Content
返回顶部 投诉反馈

© 2016 - 2022 掌控者 All Rights Reserved.