缓冲区溢出如何用于利用计算机?

时间:2009-01-20 08:59:56

标签: security buffer-overflow exploit

buffer overflows如何用于利用计算机?

如何通过导致stackheap溢出来执行任意代码?

我知道程序存储器的某些部分被覆盖了,但是我不知道这会导致一个人执行自己的代码。此外,第三方的恶意代码必须用目标处理器汇编语言编写吗?

5 个答案:

答案 0 :(得分:16)

这是有关该主题的最广为人知的文件:Smashing the Stack for Fun and Profit

但是,“堆栈溢出”与缓冲区溢出无关。堆栈溢出通常只是坏代码中的错误情况,不能用于崩溃之外的任何事情(DoS)。

编辑:您还询问了堆溢出问题。这是一个关于这个主题的好文件:http://www.w00w00.org/files/articles/heaptut.txt

答案 1 :(得分:8)

当您跳转到子例程时,堆栈包含数据和返回地址。如果您设法将特定地址放在返回地址所在的堆栈上,则可以强制CPU跳转到特定的内存位置,即您自己的代码所在的位置。这是缓冲区溢出。堆溢出有点不同,更难以利用。

堆栈溢出只是表明你的堆栈空间不足(通常更有限,特别是在内核中)。

答案 2 :(得分:7)

想象一下街上有两栋房子。一个是你朋友的房子,一个是他邪恶的偏执邻居的房子三个门。邪恶的偏执邻居永远不会进入或离开,他的地方被锁紧。

现在,你的朋友是一个如此善于信任的朋友,他会让你在他的位置存放任何东西,一个接一个地放下盒子,从一面墙开始。事实上,他是一个很好的朋友,他会一个接一个地放下盒子,没有检查他是否撞到了墙上,直到他们继续在半空中,最后穿过街道上的另外两个房子进入邪恶的偏执邻居的房子。但是你的朋友相信你不会这样做,因为他喜欢你(而且他有点幼稚)。

所以你有机会利用你这位善良信任的朋友,把一些东西放进邪恶的偏执邻居家里。


替换以下术语,您将看到缓冲区溢出攻击的类比:

  • “你朋友的家” - > “程序的一部分,不检查缓冲区溢出”
  • “他邪恶的偏执邻居的房子” - > “应该是安全的程序的另一部分”
  • “盒子” - > “程序的参数/参数,不检查缓冲区溢出”

只有当有人知道内存的安全区域在哪里,并且必须作为参数传递给所讨论的程序时才会成功,这将最终进入安全区域,以获得所需的效果。 (无论是数据还是导致执行者代码执行的代码)

答案 3 :(得分:5)

几乎所有现代处理器在调用子程序时,都会将返回地址推送到与本地数据(堆栈)相同的区域。对于不检查变量上限的例程(特别是strcpy函数),可能会发生指令地址重定向(缓冲区溢出)。

void make(char *me)
{
    char sandwich[4]; // local data, this is in stack.  the buffer for data is too small
    strcpy(sandwich, me);
    puts(sandwich);

    // implicit "return;" the return instruction(RET on Intel) instructs the processor to implicitly pop an address from stack then resume execution on that address
}

void main()
{
    // calling a subroutine (CALL on Intel) implicitly instructs the processor to push the next instruction's address(getchar line) on stack before jumping to make.
    make("Love Not War"); 
    getchar();

    puts("This will not execute.  The address to next instruction(getchar) gets overwritten with Not War");

}

“此外,第三方的恶意代码必须用目标处理器汇编语言编写吗?”的

堆栈溢出可能发生在正常运行的程序中,例如递归例程(调用自身的函数),具有忽略的终止条件。堆栈区域将填充堆栈上的大量局部变量以及返回的地址。

答案 4 :(得分:1)

通常的做法是在内存中存在恶意代码。然后你创建一个缓冲区溢出:这里的魔法不是让它只是溢出,而是正如你已经提到的那样,程序存储器的某些部分会被覆盖。由于堆栈不仅包含变量,而且当函数被称为返回地址时,会尝试使用恶意代码的地址覆盖此变量。当具有缓冲区溢出的函数返回其调用者时,该函数不会返回其原始调用者,而是返回恶意子例程。由于现在执行的代码通常具有调用代码的特权,因此尝试在代码中查找/创建此溢出,该代码具有比恶意代码更高的权限(否则您可以通过直接调用邪恶例程来执行此操作)。