【问题标题】:Running data shellcode in c executable在 c 可执行文件中运行数据 shellcode
【发布时间】:2019-02-19 22:01:02
【问题描述】:

我正在开发这个 c 程序。我在 64 位 x64 linux 上用 gcc 编译它:

#include <stdio.h>

char buffer[]={0x90,0x90,0xC3};

int main(int argc, char *argv[])
{
    void (*fct)();
    fct=buffer;
    fct();
    return 0;
}

0x90 操作码是 NOP

0xC3 操作码为 RET

我想知道我应该怎么做才能运行这个程序。运行时出现段错误...

谢谢

【问题讨论】:

  • .data 部分可能无法执行。使用const char buffer 将其放入.rodata 部分,即(因为它作为文本段的一部分链接)。
  • 谢谢,但它不起作用
  • const char buffer[] = {...}; 对我有用,无论是否优化:godbolt.org/z/0lMuL9。我在我的桌面上运行它,它没有出错就退出了。你做了什么不同的事情导致它不起作用?
  • 更新:最近的ld 版本将.rodata 放在不可执行的页面中,大概是为了减少数据作为ROP / Spectre gadgets 的暴露。

标签: assembly memory-management x86 reverse-engineering


【解决方案1】:

TL;DR 使用 -z execstack 编译,为您的可执行文件启用 Linux 的 read-implies-exec 功能。尽管名称如此,但它适用于所有页面,而不仅仅是堆栈。


程序出错是因为buffer 符号进入.data 部分,而该部分又与其他部分一起进入映射为读写但不可执行 的ELF 段。

要使buffer 可执行,最好的做法是创建一个带有RWE 标志的新ELF 段并为其分配一个新部分,然后告诉GCC 将buffer 放入这个新部分。
这可以做到,原则上使用以下链接器脚本:

PHDRS
{
        MYSEG PT_LOAD FLAGS (7);
}
SECTIONS
{
        MYSECT : { *(MYSECT) } : MYSEG
}

,改变来源:

#include <stdio.h>

char buffer[] __attribute__ ((section ("MYSECT"))) ={0x90,0x90,0xC3};

int main(int argc, char *argv[])
{
    void (*fct)();
    fct=buffer;
    fct();
    return 0;
}

以及将-T 开关传递给GCC 的编译。

但这行不通
GCC 使用基于命令行的默认链接器脚本,-T 开关完全替换它。
可以通过-Wl,-verbose 获取 GCC 使用的脚本并对其进行更新。

如果我们先用-c 调用 GCC 然后 LD 来拆分编译和链接,我们将只得到一个段,因为这是我们在链接器脚本中放入的 - 从而使我们所有的努力都失败了 only buffer 唯一的可执行数据。


对于-z execstack,我们实际上只告诉 GCC 使用设置GNU_STACK ELF 段 RWE 的链接器脚本。
这是加载程序用来设置堆栈页面的正确权限的标记段(大小和 lma 为零)。
But in truth it is used as a compatibility switch - 当堆栈设置为可执行时,加载程序将设置 all em> 可写页面作为可执行文件。

如果你使用 shellcodes -z execstack 会很容易,但是它会使你的应用程序暴露在大量的攻击之下,但我想这就是你首先需要的。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 1970-01-01
  • 2015-10-31
相关资源
最近更新 更多