如何將防寫腳本的 $0(第零個參數)偽造為我沒有寫訪問權限的路徑?
據說依靠 $ 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
那將設置
$0
為foobar
,然後簡單地輸入/tmp/a1.sh
。