如何在不使用格式字符串的情况下使用不可执行的堆栈执行特定的 shellcode?(没有 ASLR 和堆栈 cookie)

逆向工程 缓冲区溢出 外壳代码
2021-07-10 08:34:47

首先,我们没有 ASLR 和堆栈 cookie,并假设我们无法在此系统上创建自己的文件

所以我试图在这段代码中执行一个 shellcode,这是我到目前为止所做的:

我已经设法覆盖缓冲区并将函数 foo 的返回地址设置为函数关键,但我的问题是如何在此处运行特定的 shellcode?execv 将运行 bin/sh,但我不能用 shellcode 替换第一个参数,它不起作用,我不确定是否可以使用 execv 运行 shellcode,以及当我将 shellcode 传递给sh 它不起作用。

我也知道返回到 libc 漏洞,但仍然不知道如何使用 system() 执行 shellcode?甚至可以将shellcode传递给它吗?或者我可以使用另一个函数来传递一个shellcode给它?

我假设如果我们创建了自己的 shellcode 文件并替换了 sh 路径,我们就可以运行我们自己的 shellcode,但是我们无权创建文件,我们只能使用此代码来完成。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int bar(char *arg, char *out)
    {
      strcpy(out, arg);
      return 0;
    }

    int foo(char *arg)
    {
      char buffer1[100]="Test program.\n";
      char buffer2[100];
      bar(arg, buffer2);
      printf("%s",buffer1);
      return 0;
    }

    void critical()
    {
      char *msg[]={"/bin/sh",NULL};
      execv(msg[0],msg);
    }

    int main(int argc, char *argv[])
    {
      if (argc != 2)
      {
        fprintf(stderr, "prog_vuln2: argc != 2\n");
        exit(EXIT_FAILURE);
      }
      foo(argv[1]);
      return 0;
    }
2个回答

当您拥有不可执行的堆栈时,首先想到的是面向返回的编程,顾名思义,它使用返回来执行您想要的代码。
使用 ROP 时,您将需要使用程序的可执行文件和 dll(或 linux 的 .so 文件),并尽可能少地依赖系统 dll,因为它们随操作系统版本而变化。
这个想法是你找到一堆指令序列。每一个都称为一个gadget小工具可以通过pop从堆栈中mov读取一个值一个值或添加/减去一个寄存器来设置寄存器值,然后是ret(这意味着您通常可以在函数末尾找到它们),使它们返回到下一个值在堆栈上(预期返回地址所在的位置),创建一个ROP Chain.

一个简单的例子是当你想使用system.
您可以(在 64 位操作系统上)跳转到弹出返回,其中堆栈上的第一个值是您的缓冲区地址,第二个值是 的地址system,从而导致系统以您的缓冲区作为正确寄存器中的参数被调用(Linux 为 rdi,Windows 为 ecx)。
在 32 位操作系统上,溢出稍微简单一些。您所需要的只是将返回地址改为system并将其后的 4 个字节覆盖为您的缓冲区地址。这将以system您的缓冲区作为第一个参数执行。

您无法将 shellcode 传递给 execv() 是正确的,但这不是想法。您需要的是将调用 foo() 的返回地址更改为指向critical(),以便 execv() 接收路径“/bin/sh”作为参数。通常,您的 shellcode 将是critical() 本身的内容,并且返回地址将指向保存critical() 函数的缓冲区。