缓冲区溢出如何用于利用计算机?
我知道程序内存的某些部分被覆盖了,这是不应该的,但我不明白这如何导致执行他们自己的代码。另外,第三方的恶意代码必须用目标处理器的汇编语言编写吗?
这是关于该主题的最广为人知的文档:Smashing the Stack for Fun and Profit
但是,“堆栈溢出”与缓冲区溢出无关。堆栈溢出通常只是错误代码中的错误情况,不能用于崩溃 (DoS) 之外的任何事情。
编辑:您还询问了堆溢出。这是一个关于这个主题的好文档:http ://www.w00w00.org/files/articles/heaptut.txt
当您跳入子程序时,堆栈包含数据和返回地址。如果您设法将特定地址放在返回地址所在的堆栈上,则可以强制 CPU 跳转到特定的内存位置,即您放置自己的代码的位置。那是缓冲区溢出。堆溢出有点不同,更难利用。
堆栈溢出只是表明您已用完堆栈空间(通常更有限,尤其是在内核中)。
想象街道上有两座房子。一个是你朋友的房子,一个是他邪恶的偏执狂邻居的房子,三个门。邪恶的偏执邻居从不进出,他的地方被锁得很紧。
现在,你的朋友是一个非常值得信赖的朋友,他会让你在他的地方存放任何东西,一个接一个地放下箱子,从一面墙开始。事实上,他是个好朋友,他会一个接一个地放下箱子,不检查他是否撞到墙上,直到他们在半空中继续前进,最后穿过街上的另外两间房子,进入邪恶的偏执狂邻居的房子。但是你的朋友相信你不会那样做,因为他喜欢你(而且他有点天真)。
因此,您有机会通过利用您信任的好朋友,将一些东西放入邪恶的偏执邻居的房子里。
替换以下术语,您将看到与缓冲区溢出攻击的类比:
只有当有人弄清楚内存的安全区域在哪里,以及必须将什么作为参数传递给相关程序时,这才是成功的,这最终会在安全区域中产生预期的效果。(无论是数据,还是导致漏洞利用者代码被执行的代码)
几乎所有现代处理器在调用子程序时都会将返回地址推送到与本地数据(堆栈)相同的区域。对于不检查变量上限的例程(特别是 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");
}
“另外,第三者的恶意代码必须用目标处理器的汇编语言编写吗?” 是的
正常运行的程序可能会发生堆栈溢出,例如递归例程(调用自身的函数)忽略了终止条件。堆栈区域将充满堆栈上的许多局部变量以及返回地址。
通常的方法是你在内存中的某个地方有恶意代码。然后你创建一个缓冲区溢出:这里的魔法不是让它溢出,而是正如你已经提到的,程序内存的某些部分被覆盖。由于堆栈不仅包含变量,而且当一个函数被调用时返回地址,一个人试图用你的恶意代码的地址覆盖这个地址。当缓冲区溢出的函数返回其调用者时,该函数不会返回其原始调用者,而是返回到恶意子程序。由于现在执行的代码通常具有调用代码的权限,因此尝试在比邪恶代码具有更高权限的代码中查找/创建此溢出(否则您可以通过直接调用邪恶例程来做到这一点)。