我試圖了解如何使用個性系統呼叫使行程堆疊可執行,所以我撰寫了這段代碼,該代碼創建一個新行程并在堆疊上運行一個 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;
}
編譯gcc file.c -o file.o
$ uname -r
4.4.179-0404179-generic
$ readelf -l
...
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
uj5u.com熱心網友回復:
有兩個問題:
流程啟動后,您無法更改流程的個性。Doing本身
personality(READ_IMPLIES_EXEC)不會做任何事情,它只是設定當前行程的個性值(一個簡單的 32 位整數),僅此而已。為了使更改生效,需要執行一個新程式(即通過)。當前行程(及其子行程)不會受到影響。execveREAD_IMPLIES_EXEC如果 ELF 包含一個PT_GNU_STACK程式頭,指定堆疊不應該是可執行的,Linux 將忽略個性標志,這通常是編譯器的默認選擇。
默認情況下,GCC 將創建帶有PT_GNU_STACK標志設定為 RW 而不是 RWX 的程式頭的 ELF。為了有一個可執行堆疊,你必須-z execstack在編譯時將選項傳遞給 GCC,它將設定PT_GNU_STACK為 RWX。你可以檢查這個readelf -l your_elf(注意:readelf將顯示E而不是X程式頭標志)。
因此,在你的情況下,gcc -zexecstack -o file file.c應該做你想做的,你不需要打電話personality()也不需要fork()真的。只需將您的 shellcode 放入堆疊并跳入其中。從理論上講,您還可以在 ELF 檔案中找到程式頭并PT_GNU_STACK手動編輯標志 (7 = RWX),例如使用十六進制編輯器,但這比需要的作業要多。
所以,在一天結束時:
我正在嘗試了解如何使用個性系統呼叫使行程堆疊可執行
你不能。Personality 只影響新的執行,而不是已經存在的執行,并且在 ELF 屬性(如PT_GNU_STACK程式頭)之上取代了個性。但是,您可以按照上面的說明重新編譯您的程式。
注意:您仍然可以使用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/[email protected]
*
*/
#define elf_read_implies_exec(ex, executable_stack) \
(mmap_is_ia32() && executable_stack == EXSTACK_DEFAULT)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/519521.html
