Scripting

如何將防寫腳本的 $0(第零個參數)偽造為我沒有寫訪問權限的路徑?

  • March 20, 2022

據說依靠 $ 0 in a script is dangerous (often citing to fake it: exec -a …). Yes, in dirs where I have write-access I can symlink to a script to fake its $ 0. 但是如何讓$0指向我沒有寫權限的路徑(比如下面的/bin/pwd)?

下面,如果我的腳本使用 shebang,我無法實現它。當目標腳本使用shebang時可以完成嗎?

$ (exec -a /bin/pwd /tmp/a0.sh)
no-shebang: argv0=/bin/pwd /proc/.../cmdline=/bin/bash^@--noediting^@-i^@

$ (exec -a /bin/pwd /tmp/a1.sh)
yes-shebang: argv0=/tmp/a1.sh /proc/.../cmdline=/bin/sh^@/tmp/a1.sh^@

$ head /tmp/a0.sh /tmp/a1.sh
==> /tmp/a0.sh <==
echo no-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)

==> /tmp/a1.sh <==
#!/bin/sh
echo yes-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)

也就是說,如果一個腳本(及其父目錄)是防寫的,並且使用了 shebang,那麼它對 $0 的使用是安全的(防止偽造另一個防寫的路徑)?

這裡使用(在 centos 7 上)bash 的 exec 語句作為 $0 的簡單偽造。使用 execve() 的 C 程序不會有所不同嗎?是否未能在 execve() 下游(在核心或 shebang-target 中)偽造它,而不是 bash 的 exec 太弱?

編輯:C 中的 execve() 也不會在 shebang 情況下偽造 $0,輸出與上面相同:

#include <stdio.h>
int main(void) {
 char* argv[] = { "/bin/pwd", NULL };
 execve("/tmp/a1.sh", argv, NULL);
 perror(NULL);
}

我知道如果使用者獲得root,那麼假 $ 0 is least of your issues. But MY write-protected scripts, with shebang, cannot be $ 0 被非 root 使用者偽造(到另一個防寫的路徑):$0 的危險(‘just use exec -a …’)似乎是錯誤的。

好吧,手冊execve(2)說:

解釋器腳本

解釋器腳本是一個啟用了執行權限的文本文件,其第一行的格式為:

#!interpreter [optional-arg]

解釋器必須是執行檔的有效路徑名。

如果 execve() 的路徑名參數指定了解釋器

腳本,那麼解釋器將使用以下

參數呼叫:

interpreter [optional-arg] pathname arg...

因此,當您執行時exec -a /bin/pwd /tmp/a1.sh,系統會執行/bin/sh /tmp/a1.sh,並且當這樣啟動時,shell$0會從腳本文件的名稱中設置。

shell 獲得的值argv[0]不會出現,例如exec -a foobar /bin/sh /tmp/a1.sh仍會顯示/tmp/a1.sh在 中$0,並且從 的內容/proc/.../cmdline看來,執行腳本時設置的值無論如何都會失去。

但這並不意味著腳本看到的值$0不能被偽造:使用者可以對腳本創建符號連結並通過連結呼叫它,或者執行以下操作:

/bin/sh -c ". /tmp/a1.sh" foobar

那將設置$0foobar,然後簡單地輸入/tmp/a1.sh

引用自:https://unix.stackexchange.com/questions/696119