程序啟動後更改 /proc/PID/environ
$ k=v p & [1] 3028
有什麼辦法可以在仍在執行時更改不提及
p
的內容嗎?/proc/3028/environ``k=v
p
在 Linux 上,您可以覆蓋堆棧上環境字元串的值。
因此,您可以通過用零或其他任何內容覆蓋條目來隱藏條目:
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char* argv[], char* envp[]) { char cmd[100]; while (*envp) { if (strncmp(*envp, "k=", 2) == 0) memset(*envp, 0, strlen(*envp)); envp++; } sprintf(cmd, "cat /proc/%u/environ", getpid()); system(cmd); return 0; }
執行為:
$ env -i a=foo k=v b=bar ./wipe-env | hd 00000000 61 3d 66 6f 6f 00 00 00 00 00 62 3d 62 61 72 00 |a=foo.....b=bar.| 00000010
已
k=v
被 覆蓋\0\0\0
。請注意,
setenv("k", "", 1)
覆蓋該值將不起作用,因為在這種情況下,"k="
會分配一個新字元串。如果您沒有使用/以其他方式修改
k
環境變數,那麼您還應該能夠執行類似的操作來獲取堆棧上字元串的地址(嗯,其中之一):setenv()``putenv()``k=v
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char* argv[]) { char cmd[100]; char *e = getenv("k"); if (e) { e -= strlen("k="); memset(e, 0, strlen(e)); } sprintf(cmd, "cat /proc/%u/environ", getpid()); system(cmd); return 0; }
但是請注意,它僅刪除環境中收到的條目之一**。**
k=v
通常,只有一個,但沒有什麼能阻止任何人在傳遞給的 env 列表中同時傳遞k=v1
和k=v2
(或k=v
兩次)execve()
。這一直是過去安全漏洞(例如CVE-2016-2381)的原因。當以相同的名稱導出變數和函式時,它可能真的發生bash
在 shellshock 之前。在任何情況下,總會有一個小視窗,在此期間 env var 字元串尚未被覆蓋,因此您可能希望找到另一種方法將秘密資訊傳遞給命令(例如管道),如果通過
/proc/pid/environ
是一個問題。另請注意,與 , 相反
/proc/pid/cmdline
,/proc/pid/environment
只能由具有相同 euid 或 root 的程序訪問(或僅當程序的 euid 和 ruid 看起來不同時才可訪問)。您可以在 中向他們隱藏該值
/proc/pid/environ
,但他們仍然可以獲取您在記憶體中對字元串所做的任何其他副本,例如通過將調試器附加到它。請參閱https://www.kernel.org/doc/Documentation/security/Yama.txt以了解至少防止非 root 使用者這樣做的方法。