缓冲区溢出的例子?
Example of Buffer Overflow?
我在我的书中读到有关缓冲区溢出的内容并看到:
字符串加载到内存的顺序是否正确?在 little endian 中,我读到我们在较低地址的较低索引处加载位,但此示例显示相反的情况。
现在给定这段代码:
如何将 auth_flag 设置为 1? ascii 值为 1 的字符串不可打印,因此这似乎无法利用,对吗?
代码示例1:
In little endian I read that we load the bits at lower index in lower addresses but this example shows the opposite.
当使用简单的 C 风格字符串时,字节顺序不适用。 Endianess 与多字节值相关,但与 char 值无关。
代码示例2:
The string which has an ascii value of 1 isn't printable so this seems as impossible to exploit, am I right?
不对,你这里有一个基本的误解。您不需要将数值 1 放入 auth_flag
。您只需要 非零 值。
记住
if (check_authentication(argv[1])) {
真的
if (check_authentication(argv[1]) != 0) {
^^^^
因此 if 条件对于任何非零 return 值都为真。
要破坏身份验证检查,想法是编译器将 auth_flag
放在内存中的某处 password_buffer
之后。在这种情况下,您可以为程序提供一个长度超过 16 个字符的开始参数,以便多余的字符溢出缓冲区并在 auth_flag
.
的位置结束
这里是您的代码的重写。原理是一样的。我只是使用了更短的名称并删除了一些(不必要的)代码以使示例变得简单。我还打印了变量的位置。
int ca(char* pw)
{
int af = 0;
char pw_b[16];
printf("af location: %p\n", (void*)&af);
printf("pw_b location: %p\n", (void*)pw_b);
strcpy(pw_b, pw);
return af;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("wrong usage\n");
return 0;
}
if (ca(argv[1]))
{
printf("Did it...\n");
}
else
{
printf("Failed to break in\n");
}
return 0;
}
用 gcc -O0
编译 我在开始时得到这个输出 ./prog abc
af location: 0x7ffd579e13cc
pw_b location: 0x7ffd579e13b0
Failed to break in
从这里我可以看到 af
位于 0x1c 字节(或 28 位十进制)after pw_b
。所以如果我给程序一个超过 28 个字符的参数,它可能会覆盖 af
(如果它没有因为其他原因崩溃....)。
所以我尝试了 ./prog 1234567890123456789012345678b
(注意字符串中有 29 个字符),我得到:
af location: 0x7ffc63312f8c
pw_b location: 0x7ffc63312f70
Did it...
所以我成功了...我破解了验证码。
但是请注意...在另一个系统上,使用另一个编译器,使用其他编译器选项等,情况可能会有所不同。所以你不能确定在你的系统上重现它。也许您需要不同的输入,也许在您的系统上什至不可能。首先检查变量所在的位置,然后计算所需的输入。
我在我的书中读到有关缓冲区溢出的内容并看到:
字符串加载到内存的顺序是否正确?在 little endian 中,我读到我们在较低地址的较低索引处加载位,但此示例显示相反的情况。
现在给定这段代码:
如何将 auth_flag 设置为 1? ascii 值为 1 的字符串不可打印,因此这似乎无法利用,对吗?
代码示例1:
In little endian I read that we load the bits at lower index in lower addresses but this example shows the opposite.
当使用简单的 C 风格字符串时,字节顺序不适用。 Endianess 与多字节值相关,但与 char 值无关。
代码示例2:
The string which has an ascii value of 1 isn't printable so this seems as impossible to exploit, am I right?
不对,你这里有一个基本的误解。您不需要将数值 1 放入 auth_flag
。您只需要 非零 值。
记住
if (check_authentication(argv[1])) {
真的
if (check_authentication(argv[1]) != 0) {
^^^^
因此 if 条件对于任何非零 return 值都为真。
要破坏身份验证检查,想法是编译器将 auth_flag
放在内存中的某处 password_buffer
之后。在这种情况下,您可以为程序提供一个长度超过 16 个字符的开始参数,以便多余的字符溢出缓冲区并在 auth_flag
.
这里是您的代码的重写。原理是一样的。我只是使用了更短的名称并删除了一些(不必要的)代码以使示例变得简单。我还打印了变量的位置。
int ca(char* pw)
{
int af = 0;
char pw_b[16];
printf("af location: %p\n", (void*)&af);
printf("pw_b location: %p\n", (void*)pw_b);
strcpy(pw_b, pw);
return af;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("wrong usage\n");
return 0;
}
if (ca(argv[1]))
{
printf("Did it...\n");
}
else
{
printf("Failed to break in\n");
}
return 0;
}
用 gcc -O0
编译 我在开始时得到这个输出 ./prog abc
af location: 0x7ffd579e13cc
pw_b location: 0x7ffd579e13b0
Failed to break in
从这里我可以看到 af
位于 0x1c 字节(或 28 位十进制)after pw_b
。所以如果我给程序一个超过 28 个字符的参数,它可能会覆盖 af
(如果它没有因为其他原因崩溃....)。
所以我尝试了 ./prog 1234567890123456789012345678b
(注意字符串中有 29 个字符),我得到:
af location: 0x7ffc63312f8c
pw_b location: 0x7ffc63312f70
Did it...
所以我成功了...我破解了验证码。
但是请注意...在另一个系统上,使用另一个编译器,使用其他编译器选项等,情况可能会有所不同。所以你不能确定在你的系统上重现它。也许您需要不同的输入,也许在您的系统上什至不可能。首先检查变量所在的位置,然后计算所需的输入。