我这里有一些示例代码,用于理解初学者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将指针推入堆栈,关于内存的哪些部分可执行的还有其他一些规则?我阅读了联机帮助页,但是我无法确切了解规则是什么以及如何执行它们。
另一个问题是,我认为我确实也缺少在调试时可视化内存的好工具,因此很难弄清楚这一点。任何建议将不胜感激。
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。
| 归档时间: |
|
| 查看次数: |
242 次 |
| 最近记录: |