nad*_*vin 2 c linux assembly system-calls linux-kernel
我试图了解如何使用个性系统调用使进程堆栈可执行,因此我编写了这段代码,该代码创建一个新进程并在堆栈上运行 bash,并且由于我没有堆栈上的执行权限而出现段错误。我究竟做错了什么?
#include <stdio.h>
#include <sys/personality.h>
int main()
{
setvbuf(stdout, 0, 2, 0);
unsigned char shellcode[] = "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"; // open bash
if(personality(READ_IMPLIES_EXEC | ADDR_NO_RANDOMIZE) == -1) // return 0
{
printf("personality failed");
exit(0);
}
int (*ret)() = (int(*)())shellcode;
if(fork() == 0) // child proces
ret();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译为gcc file.c -o file.o
$ uname -r
4.4.179-0404179-generic
$ readelf -l
...
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
Run Code Online (Sandbox Code Playgroud)
有两个问题:
进程启动后,您无法更改其特性。Doing本身personality(READ_IMPLIES_EXEC)不会做任何事情,它只是设置当前进程的个性值(一个简单的 32 位整数),仅此而已。为了使更改生效,需要执行一个新程序(即通过execve)。当前进程(及其子进程)不会受到影响。
READ_IMPLIES_EXEC如果 ELF 包含PT_GNU_STACK指定堆栈不应可执行的程序头,Linux 将忽略个性标志,这通常是编译器的默认选择。
默认情况下,GCC 将创建带有PT_GNU_STACK程序头的 ELF,其标志设置为 RW 而不是 RWX。为了拥有可执行堆栈,您必须-z execstack在编译时将选项传递给 GCC,该选项将设置PT_GNU_STACK为 RWX。您可以使用readelf -l your_elf(注意:readelf将显示E而不是X程序头标志)进行检查。
因此,就您的情况而言,应该做您想做的事情,并且您不需要真正gcc -zexecstack -o file file.c打电话。只需将您的 shellcode 放入堆栈并跳转到其中即可。理论上,您还可以在 ELF 文件中找到程序头并手动编辑标志(7 = RWX),例如使用十六进制编辑器,但这会比需要的工作更多。personality()fork()PT_GNU_STACK
所以,归根结底:
我试图了解如何使用个性系统调用使进程堆栈可执行
你不能。个性仅影响新的执行,而不影响现有的执行,并且除此之外,PT_GNU_STACK程序头等 ELF 属性会取代个性。但是,您可以按照上面的说明重新编译您的程序。
注意:尽管如此,您仍然可以将mprotect()堆栈内存页的权限更改为 RWX,因为您可以在运行时以某种方式推断堆栈基地址和大小(例如,获取函数中局部变量的地址并将最低 12 位清零) )。
对于像您的内核 (4.4) 这样的旧内核来说,这已经足够了,但从 Linux v5.8 开始,情况就更加微妙了。假设您使用的是 x86,您可以查看源代码中的此注释以获取解释:
/*
* An executable for which elf_read_implies_exec() returns TRUE will
* have the READ_IMPLIES_EXEC personality flag set automatically.
*
* The decision process for determining the results are:
*
* CPU: | lacks NX* | has NX, ia32 | has NX, x86_64 |
* ELF: | | | |
* ---------------------|------------|------------------|----------------|
* missing PT_GNU_STACK | exec-all | exec-all | exec-none |
* PT_GNU_STACK == RWX | exec-stack | exec-stack | exec-stack |
* PT_GNU_STACK == RW | exec-none | exec-none | exec-none |
*
* exec-all : all PROT_READ user mappings are executable, except when
* backed by files on a noexec-filesystem.
* exec-none : only PROT_EXEC user mappings are executable.
* exec-stack: only the stack and PROT_EXEC user mappings are executable.
*
* *this column has no architectural effect: NX markings are ignored by
* hardware, but may have behavioral effects when "wants X" collides with
* "cannot be X" constraints in memory permission flags, as in
* https://lkml.kernel.org/r/20190418055759.GA3155@mellanox.com
*
*/
#define elf_read_implies_exec(ex, executable_stack) \
(mmap_is_ia32() && executable_stack == EXSTACK_DEFAULT)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
483 次 |
| 最近记录: |