0x0d 和 0xff(来自终结者金丝雀)防止哪些字符串操作

What string operations do the 0x0d and 0xff (from a terminator canary) protect against

表示here:

A terminator canary contains NULL(0x00), CR (0x0d), LF (0x0a) and EOF (0xff) -- four characters that should terminate most string operations, rendering the overflow attempt harmless.

我知道 null (0x00) 可以帮助防止 strcpy、strncpy、stpcpy 和 strcat。 LF (0x0A) 也可以用于 gets 和 fgets。

什么是 0x0D 和 0xFF 适合停止?

"canary" 的目的是检测缓冲区何时溢出。它位于堆栈的 return 地址之前,在当前堆栈帧中分配的任何缓冲区之后。如果它的值发生变化,那么堆栈检查代码就会知道缓冲区已经溢出并在程序造成任何损害之前中止程序。

问题在于,如果攻击者用与之前相同的值覆盖金丝雀,则不会检测到缓冲区溢出。为了使这更困难,要么使用随机数作为金丝雀,这样攻击者就无法预测它,要么使用您询问的特殊 "terminator canary" 值。选择组成终结器金丝雀的字节值是因为它们将终止程序使用的各种复制操作。如果这些值在字符串 ("shellcode") 中,攻击者用来尝试覆盖 return 值,那么大多数复制字符串的代码将在覆盖 return 值之前停止。

以下是内存复制操作的示例,如果终止金丝雀出现在源输入中,这些操作将在覆盖 return 值之前终止:

NUL终止

char buf[10];

strcpy(buf, src);

上面的例子是最常见的情况。任何复制 C 字符串的操作都会在源字符串的第一个 NUL (0) 字节处停止。

EOL 终止

char buf[10];

gets(buf);

使用 gets 是初学者常见的错误,通常不会出现在生产代码中,但是编写更复杂的代码来读取一行但不注意不要溢出缓冲区并不难。标记行尾的内容取决于惯例。通常的 Unix 约定是使用单个换行符 (LF, 0x0A),但是 Windows 使用回车符 return 和换行符 (CR LF, 0x0D 0x0A) 序列。由于终止符 canary 包含 CR 和 LF 字节值,因此两个 EOL 终止符都存在于 canary 中。任何复制单行的操作都将在覆盖 return 值之前停止。

损坏的 EOF 终止

char buf[10];
char *dest = buf;

while(1) {
    char c = getchar();
    if (c == EOF) {
        break;
    }
    *dest++ = c;
}

与其他两个示例相比,EOF 终止符在这里的工作原理更难理解和解释。除了缓冲区溢出错误之外,此代码还包含另一个导致 0xFF 被解释为 EOF 的错误。与使用 gets 一样,这也是菜鸟错误,但在生产代码中更常见。该错误是由于使用 char c 而不是 int c 引起的。

getchar 编辑的值 return 实际上是 int 而不是 char。这使得将有效字节值与特殊 EOF return 值区分开来成为可能,后者在大多数系统上为 -1。从文件中读取的字节值被 return 编辑为 unsigned char 值转换为 int。因此,文件中的字节值 '\xFF' 被 return 编辑为 int 值 255。当它被分配给 char 变量 c 时,它从(大多数这些天的系统) 一个 32 位有符号整数值到一个 8 位有符号整数值。这会将 32 位有符号整数值 255 转换为 8 位有符号整数值 -1。此转换还将 32 位有符号整数值 -1 (EOF) 转换为 8 位有符号整数值 -1。

由于 '\xFF' 和 EOF 最终都被转换为 -1,因此它们最终都与 EOF 进行比较。这意味着在上面的示例代码中,当任一值被 getchar 编辑为 return 时,循环将终止。任何犯这种错误的代码都将在源输入的第一个 '\xFF' 字节处停止复制。然而,正确使用 getchargetcfgetc 或类似函数的代码,将 return 值分配给 int,将继续复制过去的任何 ' \xFF' 字节。

总结

终结者金丝雀使得攻击者无法利用代码中的给定缓冲区溢出,如果溢出代码使用 NUL (0)、EOL (0x0D and/or 0x0A) 或损坏的 EOF ( 0xFF) 比较终止复制。我的猜测是,大多数缓冲区溢出的情况都是由于 NUL 在终结者金丝雀中而无法利用的。许多剩余字符将受到 EOL 字符的保护,而损坏的 EOF 字节可能根本没有太多适用性。