C中的缓冲区溢出

我试图在Mac OS X 10.6 64位上使用C编写一个简单的缓冲区溢出。 这是概念:

void function() { char buffer[64]; buffer[offset] += 7; // i'm not sure how large offset needs to be, or if // 7 is correct. } int main() { int x = 0; function(); x += 1; printf("%d\n", x); // the idea is to modify the return address so that // the x += 1 expression is not executed and 0 gets // printed return 0; } 

这是main的汇编程序转储的一部分:

 ... 0x0000000100000ebe : callq 0x100000e30  0x0000000100000ec3 : movl $0x1,-0x8(%rbp) 0x0000000100000eca : mov -0x8(%rbp),%esi 0x0000000100000ecd : xor %al,%al 0x0000000100000ecf : lea 0x56(%rip),%rdi # 0x100000f2c 0x0000000100000ed6 : callq 0x100000ef4  ... 

我想跳过movl指令,这意味着我需要将返回地址递增42 – 35 = 7(正确吗?)。 现在我需要知道返回地址的存储位置,以便我可以计算出正确的偏移量。

我已经尝试手动搜索正确的值,但是1被打印或我得到abort trap – 是否有某种缓冲区溢出保护正在进行?


在我的机器上使用88的偏移量。 我用Nemo的方法找出了返回地址。

这个32位示例说明了如何解决这个问题,请参阅下面的64位:

 #include  void function() { char buffer[64]; char *p; asm("lea 4(%%ebp),%0" : "=r" (p)); // loads address of return address printf("%d\n", p - buffer); // computes offset buffer[p - buffer] += 9; // 9 from disassembling main } int main() { volatile int x = 7; function(); x++; printf("x = %d\n", x); // prints 7, not 8 } 

在我的系统上,偏移量是76.这是缓冲区的64个字节(记住,堆栈增长,因此缓冲区的起点远离返回地址)加上其他任何碎屑。

显然,如果你正在攻击一个现有的程序,你不能指望它为你计算答案,但我认为这说明了原理。

(另外,我们很幸运, +9不执行另一个字节。否则单字节增量不会设置返回地址我们的预期。如果你不幸在main返回地址,这个例子可能会中断)

我以某种方式忽略了原始问题的64位。 x86-64的等价物是8(%rbp)因为指针长度为8个字节。 在这种情况下,我的测试构建恰好产生104的偏移量。在上面的代码中,使用double %%替换8(%%rbp)以在输出程序集中获得单个% 。 这在ABI文档中有所描述。 搜索8(%rbp)

评论中有一个抱怨,即4(%ebp)76或其他任意数字一样神奇。 事实上,寄存器%ebp (也称为“帧指针”)的含义及其与堆栈上返回地址位置的关系是标准化的。 我快速用Google搜索的一个例子就在这里 。 该文使用术语“基指针”。 如果您想在其他体系结构上利用缓冲区溢出,则需要详细了解该CPU的调用约定。

Roddy是对的,你需要操作指针大小的值。

我将首先阅读您的漏洞利用函数中的值(并打印它们),而不是编写它们。 当您爬过数组的末尾时,您应该开始从堆栈中查看值。 不久之后,您应该找到返回地址,并能够将其与反汇编程序转储对齐。

反汇编function()并查看它的外观。

偏移量需要为负值 ,可能为64 + 8,因为它是64位地址。 此外,您应该在指针大小的对象上执行’+7’,而不是在char上。 否则,如果两个地址跨越256字节边界,您将利用您的漏洞….

您可以尝试在调试器中运行代码,一次步进每个组装线,并检查堆栈的内存空间和寄存器。

我总是喜欢操作不错的数据类型,比如这个:

 struct stackframe { char *sf_bp; char *sf_return_address; }; void function() { /* the following code is dirty. */ char *dummy; dummy = (char *)&dummy; struct stackframe *stackframe = dummy + 24; /* try multiples of 4 here. */ /* here starts the beautiful code. */ stackframe->sf_return_address += 7; } 

使用此代码,您可以轻松地与调试器一起检查stackframe->sf_return_address中的值是否符合您的期望。