试图实现enable_execute_stack(Mac OS X)

时间:2015-06-24 04:46:38

标签: c macos

我已下载并编译了Apples源代码并将其添加到Xcode.app/Contents/Developer/usr/bin/include/c++/v1。现在我如何在C中实现?我正在处理的代码来自关于Hackadays shellcode执行者的this帖子。我的代码目前是这样的:

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

unsigned char shellcode[] = "\x31\xFA......";

int main()
{
  int *ret;
  ret = (int *)&ret + 2;
  (*ret) = (int)shellcode;
  printf("2\n");
}

我用两者编译:

gcc -fno-stack-protector shell.c
clang -fno-stack-protector shell.c

我想我的最后一个问题是,如何告诉编译器实现“__enable_execute_stack”?

2 个答案:

答案 0 :(得分:1)

堆栈保护程序与可执行堆栈不同。这引入了金丝雀来检测堆栈何时被破坏。

要获得可执行堆栈,您必须链接说使用可执行堆栈。毫无疑问,这是一个坏主意因为它使攻击变得更容易。

链接器的选项是-allow_stack_execute,它变成了gcc / clang命令行:

clang -Wl,-allow_stack_execute -fno-stack-protector shell.c
但是,您的代码不会尝试在堆栈上执行代码,但它会尝试更改少量的堆栈内容,尝试完成返回shellcode,这是最常见的{{{ 3}}攻击。

在通常编译的ROP上,这将尝试覆盖所谓的链接区域(这是在函数返回时将调用的下一条指令的地址)。这假定代码未使用-fomit-frame-pointer进行编译。如果它是用这个选项编译的,那么你实际上是在移动一个额外的地址。

在OSX 64位OSX 32bit environment上,寄存器为64位,所有值都需要long而不是int引用,但方式类似。

你所拥有的shellcode实际上是在你代码的数据段中(因为它是char [],这意味着它是可读/可写的,不可读的 - 可执行的。你需要mmap它(就像nneonneo的答案)或者将它复制到现在可执行的堆栈中,获取它的地址并以这种方式调用它。

然而,如果您只是想让代码运行,那么nneonneo的答案会让它变得非常简单,但是如果您尝试使用exploit-y代码,那么您将不得不做一些更多的工作。由于不可执行的堆栈,新的孩子使用返回库机制,尝试返回调用,例如,一个exec /系统调用与堆栈中的数据。

答案 1 :(得分:0)

有了现代执行保护措施,让shellcode像这样运行有点棘手。请注意,您的代码不会尝试在堆栈上执行代码;相反,它将shellcode的地址存储在堆栈中,实际代码位于程序的数据段中。

你有几个选项可以让它发挥作用:

  1. 将shellcode放在实际的可执行部分中,因此它是可执行代码。您可以使用GCC和Clang __attribute__((section("name")))执行此操作。在OS X上:

    const char code[] __attribute__((section("__TEXT,__text"))) = "...";
    

    后跟

    ((void (*)(void))code)();
    

    效果很好。在Linux上,请改为使用部分名称".text"

  2. 使用mmap创建内存的读写部分,复制shellcode,然后mprotect使其具有读取 - 执行权限,然后执行它。这就是现代JIT执行动态生成代码的方式。一个例子:

    #include <sys/mman.h>
    
    void execute_code(const void *code, size_t codesize) {
        size_t pagesize = (codesize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
        void *chunk = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
        if(chunk == MAP_FAILED) return;
        memcpy(chunk, code, codesize);
        mprotect(chunk, pagesize, PROT_READ|PROT_EXEC);
        ((void (*)(void)chunk)();
        munmap(chunk, pagesize);
    }
    
  3. 这些方法都不要求您指定任何特殊的编译器标志才能正常工作,并且它们都不需要摆弄堆栈中保存的EIP。