我正尝试在64位Mac OS X 10.6上使用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 <main+30>: callq 0x100000e30 <function>
0x0000000100000ec3 <main+35>: movl $0x1,-0x8(%rbp)
0x0000000100000eca <main+42>: mov -0x8(%rbp),%esi
0x0000000100000ecd <main+45>: xor %al,%al
0x0000000100000ecf <main+47>: lea 0x56(%rip),%rdi # 0x100000f2c
0x0000000100000ed6 <main+54>: callq 0x100000ef4 <dyld_stub_printf>
...
我想跳过movl
指令,这意味着我需要将返回地址递增42 - 35 =7(对吗?)。现在我需要知道返回地址存储在哪里,这样我才能计算正确的偏移量。
我尝试手动搜索正确的值,但要么打印出1,要么得到abort trap
--是否存在某种缓冲区溢出保护?
使用偏移量88在我的机器上工作。我使用了Nemo的方法来查找返回地址。
发布于 2011-06-03 05:03:16
此32位示例说明了如何解决此问题,请参见下面的64位示例:
#include <stdio.h>
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的偏移量。在上面的代码中,使用双%%
替换8(%%rbp)
,以获得输出程序集中的单个%
。这在this ABI document中有描述。搜索8(%rbp)
。
评论中有人抱怨说,4(%ebp)
和76
或任何其他任意数字一样神奇。实际上,寄存器%ebp
(也称为“帧指针”)的含义及其与堆栈上返回地址的位置的关系是标准化的。我很快搜索到的一个例子是here。这篇文章使用了术语“基指针”。如果您想要利用其他架构上的缓冲区溢出,则需要对该CPU的调用约定有类似的详细了解。
发布于 2011-06-03 05:02:17
Roddy是对的,你需要对指针大小的值进行操作。
我会从读取你的exploit函数中的值(并打印它们)开始,而不是写它们。当您爬行通过数组的末尾时,您应该开始看到堆栈中的值。不久,您应该找到返回地址,并能够将其与反汇编程序转储对齐。
发布于 2011-06-03 04:53:29
您可以尝试在调试器中运行代码,一次单步执行每条装配线,并检查堆栈的内存空间和寄存器。
https://stackoverflow.com/questions/6220212
复制相似问题