什么是 The poisoned NUL byte,1998 和 2014 版本?

what is The poisoned NUL byte, in 1998 and 2014 editions?

我必须就 "poisoned null-byte (glibc)" 做 10 分钟的演讲。 我搜索了很多,但一无所获,我需要帮助,因为操作系统 linux 以及内存和进程管理不是我的事。

这里是 original article, and here is an old article 关于相同问题的另一个版本。

我想要的是对问题的新旧版本的简短解释 or/and 足够的参考资料,我可以在其中更好地了解此安全威胁。

要开始了解这种攻击的工作原理,您至少需要基本了解 CPU 的工作原理、内存的工作原理、"heap" 和 "stack" 的工作原理进程是什么,指针是什么,libc 是什么,链表是什么,函数调用是如何在机器级别实现的(包括对函数指针的调用),mallocfree 函数来自什么C 库做,等等。希望您至少具备一些 C 编程的基础知识? (否则,您可能无法及时完成此作业。)

如果您对上述基本主题有一些 "gaps" 知识,请尽快翻阅书籍并填写。如果需要,请与他人交谈,以确保您了解他们。然后仔细阅读以下内容。这不会解释您链接到的文章中的所有内容,但会给您一个良好的开端。准备好了?让我们开始吧...

C 字符串是 "null-terminated"。这意味着字符串的结尾由零字节标记。因此,例如,字符串 "abc" 在内存中表示为(十六进制):0x61 0x62 0x63 0x00。请注意,由于终止空值,该 3 个字符的字符串实际上需要 4 个字节。

现在如果你这样做:

char *buffer = malloc(3); // not checking for error, this is just an example
strcpy(buffer, "abc");

...然后终止空(零字节)将超过缓冲区的末尾并覆盖一些东西。我们分配了一个 3 字节的缓冲区,但将 4 个字节复制到其中。因此,缓冲区末尾之后的字节中存储的任何内容都将被替换为零字节。

这就是 __gconv_translit_find 中发生的事情。他们有一个缓冲区,已经分配了足够的 space 来追加 ".so",包括终止空字节,到字符串的末尾。但是他们从错误的位置开始在中复制了".so"。他们开始的复制操作距离 "right" 太远了一个字节,因此终止的空字节超过了缓冲区的末尾并覆盖了一些内容。

现在,当您调用 malloc 以取回动态分配的缓冲区时,malloc 的大多数实现实际上会在缓冲区 之前存储一些内务处理数据.例如,它们可能存储缓冲区的大小。稍后,当你将该缓冲区传递给 free 以释放内存,以便它可以重新用于其他用途时,它会发现 "hidden" 数据就在缓冲区开始之前,并且会知道有多少您实际上 freeing 的内存字节数。 malloc 也可能 "hide" 同一位置的其他管理数据。 (在您提到的 2014 年文章中,malloc 的实现还在那里存储了一些 "flag" 位。)

文章中描述的攻击将精心设计的参数传递给命令行程序,旨在触发 __gconv_translit_find 中的缓冲区溢出错误,以这种方式终止空字节会清除 "flag" 由 malloc 存储的位——不是 溢出缓冲区 的标志位,而是 另一个 缓冲区的标志位在 溢出的那个之后 被分配。 (因为 malloc 在分配缓冲区的开始 之前 存储了额外的内务管理数据,并且我们结束了 运行 宁 previous buffer. 你跟上了吗?)

文章显示了一个图表,其中 0x00000201 存储在溢出的缓冲区之后。溢出的空字节擦除底部 1 并将其更改为 0x00000200。一开始这可能没有意义,直到您记住 x86 CPUs 是小端字节序——如果您不理解 "little-endian" 和 "big-endian" CPUs 是什么, 查一查。

之后,标志位被擦除的缓冲区被传递给free。事实证明,清除一个标志位 "confuses" free 并使其反过来也覆盖其他一些内存。 (你必须了解 GNU libc 使用的 mallocfree 的实现,才能理解为什么会这样。)

通过仔细选择原始程序的输入参数,您可以进行设置,使 "confused" free 覆盖的内存用于称为 tls_dtor_list 的内存。这是一个由 GNU libc 维护的链表,它包含指向某些函数的指针,当主程序退出时它必须调用这些函数。

所以tls_dtor_list被覆盖了。攻击者设置得恰到好处,因此被覆盖的 tls_dtor_list 中的函数指针将指向他们想要 运行 的一些代码。当主程序退出时,libc 中的一些代码遍历该列表并调用每个函数指针。结果:攻击者代码被执行!

现在,在这种情况下,攻击者已经可以访问目标系统。如果他们所能做的只是 运行 一些具有他们自己帐户权限级别的代码,那他们就无处可去。他们想要 运行 具有 root(管理员)权限的代码。这怎么可能?这是可能的,因为有问题的程序是一个 setuid 程序,由 root 拥有。如果您不知道 Unix 中的 "setuid" 程序是什么,请查找并确保您理解它,因为这也是整个漏洞利用的关键。

这是关于 2014 年的文章 -- 我没有看 1998 年的那篇。祝你好运!