gcc execstack标志究竟允许在什么情况下使用,以及如何执行呢?

Sam*_*m P 3 c x86 gcc

我这里有一些示例代码,用于理解初学者CTF的某些C行为:

// example.c

#include <stdio.h>


void main() {
        void (*print)();

        print = getenv("EGG");
        print();
}
Run Code Online (Sandbox Code Playgroud)

编译: gcc -z execstack -g -m32 -o example example.c

用法: EGG=$(echo -ne '\x90\xc3) ./example

如果我用execstack标志编译代码,则程序将执行我在上面注入的操作码。没有该标志,该程序将由于分段错误而崩溃。

为什么会这样呢?是因为getenv将实际的操作码存储在堆栈上,而execstack标志允许跳转到堆栈吗?还是getenv将指针推入堆栈,关于内存的哪些部分可执行的还有其他一些规则?我阅读了联机帮助页,但是我无法确切了解规则是什么以及如何执行它们。

另一个问题是,我认为我确实也缺少在调试时可视化内存的好工具,因此很难弄清楚这一点。任何建议将不胜感激。

Pet*_*des 7

getenv env var的值存储在堆栈中。从流程启动开始,它已经在堆栈中,并getenv获得指向它的指针。

请参见i386 System V ABI对argv []和envp []在进程启动时位于何处的描述:[esp]

_start不会在调用前复制它们main,只是计算指向它们的指针作为args传递给main。(链接到最新版本,网址https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI,其中维护了官方最新版本。)


您的代码正在将指向堆栈内存的指针(包含env var的值)转换为函数指针并对其进行调用。查看编译器生成的asm(例如,在https://godbolt.org/上):类似于call getenv/ call eax

-zexecstack使所有页面都可执行,而不仅仅是堆栈。它还适用于.data.bss.rodata和用malloc/ 分配的部分new

GNU / Linux上的确切机制是一个“ read-implies-exec”进程范围的标志,该标志会影响以后的所有分配,包括手动使用mmap 有关项目中包含的汇编文件的更多信息,请参见mmap在项目中包含的汇编文件中的意外执行权限GNU_STACK

有趣的事实:获取访问其父代局部变量的嵌套函数的地址会使gcc启用-zexecstack。它将可执行“蹦床”的代码存储到堆栈中,该代码将“静态链”指针传递给实际的嵌套函数,从而使其能够引用其父对象的堆栈框架。


如果您想将数据执行为不带代码的代码-zexecstack,则可以mprotect(PROT_EXEC|PROT_READ|PROT_WRITE)在包含该环境变量的页面上使用。(它是堆栈的一部分,因此您不应删除写许可权;例如,它可以与main的堆栈框架位于同一页面中。)


有关:

使用ldbinutils的GNU / Linux 大约在2018年末之前,该.rodata部分与该部分链接到相同的ELF段中.text,因此const char code[] = {0xc3}或字符串文字是可执行的。

Current ld提供.rodata了自己的段,该段被映射为不带exec的读段,因此,除非您使用,否则不再可能在只读数据中找到ROP / Spectre“小工具” -zexecstack