2 Set-UID 程式的漏洞
2.1 隐藏的輸入:環境變量
特權程式必須對所有輸入進行安全檢查。輸入檢查實際上是通路控制的一部分,特權程式必須這麼做,來確定程式的安全。很多安全問題都是輸入檢查的錯誤造成的。
如果輸入在程式中顯式存在,程式員可能記得執行輸入檢查;如果輸入隐式存在,輸入檢查可能會忘記,因為程式員可能不知道這個輸入的存在。環境變量就是這類輸入。
每個 Unix 程序都在特定環境下運作。環境由環境變量表組成,每個變量都有指派。一些程式内部使用這些環境變量,Shell 程式就是這些程式的例子。換句話說,一些環境變量的值可以 Shell 程式的行為。
由于環境變量由使用者控制,如果程式依賴這些變量,使用者可以間接影響這類程式的行為,通過修改一些環境變量的值。是以,了解特權程式是否依賴任何環境變量的值就十分重要。一種程式可能被環境變量影響的方式,就是在程式中顯式使用環境變量的值。在 C 語言中,程式可以使用
getenv
來通路環境變量的值。但是,也有許多例子,程式隐式使用環境變量。這就是我們在許多 Set-UID 程式中看到的漏洞。我們會在這一節中展示幾個例子。
-
環境變量PATH
- 在 Shell 中執行指令式,Shell 會使用
環境變量搜尋所有指令,它包含一個目錄清單。Shell 程式通過目錄清單(和他們在PATH
環境變量的相同順序)來搜尋。第一個比對指令名稱的程式會被執行。PATH
- 下面會發生什麼?要注意
庫函數首先調用system (const char *cmd)
程式,之後讓 SHell 程式執行/bin/sh
。cmd
system ("mail");
- 在 Shell 中執行指令式,Shell 會使用
- 攻擊者可以将
修改成這個,并使目前目錄下的PATH
被執行。mail
拿超人來比喻的話,如果超人的指令是“左轉”(壞人在左邊而好人在右邊,你可以假設他要攻擊壞人)。如果攻擊者準确知道左轉指令什麼時候以及在哪裡執行,他就可以做出與上面類似的攻擊。因為“左邊”是個相對的方向,并不是絕對方向。如果攻擊者事先在你想要左轉的地方,放置一個旋轉裝置,并将你旋轉 180 度,隻要你踏上了它,“左轉”就變成了轉到好人那裡。如果你遵循了指令,你最後就會攻擊好人。PATH=".:$PATH"; export PATH
-
IFS
-
變量決定了哪些字元被解釋為空白字元。它代表了内部字段分隔符。假設我們設定它來包含斜杠字元:IFS
IFS="/ \t\n"; export IFS PATH=".:$PATH"; export PATH
- 現在從 Bourne shell 中調用任何使用絕對
的程式(李儒PATH
)。它現在解釋為下面的東西,它會在目前使用者目錄下,嘗試執行指令行調用system
:bin
system("/bin/mail root"); ---> system(" bin mail root");
- IFS 的 bug 現在已經在 SHell 中禁止了;所引用的新的 Shell 程序不會繼承 IFS 變量。
- 假設在超人的故事中。超人知道使用“左轉”指令的風險,是以它将其改為“轉到北邊”,它現在是個絕對方向。這仍然存在漏洞,因為“北”由磁場決定,不幸的是,磁場可以通過攻擊者放置的磁鐵來影響。
-
-
LD_LIBRARY_PATH
- Linux 中,除非編譯時期通過
顯式指定,所有 Linux 程式需要在運作時期連結到動态連結庫。動态連結器或加載器-static
加載程式所需的共享庫,準備要運作的程式,之後運作它。你可以使用下面的指令來觀察程式需要什麼共享庫。ld.so/ld-linux.so
% ldd /bin/ls
-
是一個環境變量,被動态連結器或加載器(LD_LIBRARY_PATH
)使用。它含有一個目錄清單,讓連結器或者加載器在搜尋共享庫時尋找。可以列出多個目錄,以冒号(ld.so/ld-linux.so
)分隔。對于任何可執行檔案,這個清單放在現存的編譯器加載路徑,以及任何系統預設加載路徑的前面。:
- 基本上每個 Unix 程式都依賴于
,并且每個 Windows 程式都一拉李雨 DLL。如果這些苦可以替換為惡意的副本,惡意代碼就可以在共享庫函數被調用時執行。libc.so
- 由于
可以由使用者充值,攻擊者可以修改這個變量,并強制庫加載器在攻擊者的目錄中搜尋庫,進而加載攻擊者的惡意庫。LD_LIBRARY_PATH
% setenv LD_LIBRARY_PATH .:$LD_LIBRARY_PATH
- 為了使 Set-UID 程式更加安全,不受
環境變量的影響,運作時的連結器或加載器(LD_LIBRARY_PATH
)會忽略環境變量,如果程式是個 Set-UID 程式。ld.so
- 防護應用也可以靜态連結到可信庫來避免這個問題。
- 在 Windows 主機上,通常在加載 DLL 的時候,在搜尋系統目錄之前,會搜尋目前目錄中的 DLL。如果你點選 Word 文檔來啟動 Office,會在包含該文檔的目錄下搜尋 DLL。
- Linux 中,除非編譯時期通過
-
LD PRELOAD
- 許多 Unix 系統允許你“預加載”共享庫,通過設定環境變量
。這些使用者指定的庫會在所有其它庫之前加載。這可以用于選擇性重載其他庫中的函數。例如,如果你已經建構了一個庫,你可以使用下列指令預加載它:LD PRELOAD
如果% export LD_PRELOAD=./libmylib.so.1.0.1
包含函數libmylib.so.1.0.1
,它是個标準的sleep
函數,當程式執行并調用libc
時,sleep
中的函數會被調用。libmylib.so.1.0.1
- 許多 Unix 系統允許你“預加載”共享庫,通過設定環境變量
- 這裡是一個程式,重載了
中的libc
sleep
我們可以使用下列指令編譯程式(假設上面的程式名為#include <stdio.h> void sleep (int s) { printf("I am not sleeping!\n"); }
):name.c
現在,我們運作下列程式:% gcc -fPIC -g -c a.c % gcc -shared -o libmylib.so.1.0.1 a.o -lc
如果環境變量int main() { sleep(1); return 0; }
設為LD PRELOAD
,标準libmylib.so.1.0.1
libc
沒有使用,反之我們共享庫中的sleep
函數會調用,并且列印sleep
"I am not sleeping!"
- 為了確定 Set-UID 程式安全,不受
環境變量的控制,運作時連結器或加載器(LD PRELOAD
)會忽略這個環境變量,如果程式是 Set-Root-UID 程式,除非真實 UID 也為 0。ld.so
2.2 調用其它程式
當特權程式調用其它程式時,必須注意是否調用了非預期的程式。我們知道,環境變量是個我們需要注意的地方,也有一些我們需要注意的其它地方。
- 如果 Set-UID 程式執行下面的事情,會發生什麼?
// The contents of User_Input are provided by users. sprintf(command, "/bin/mail %s", User_Input); system(command);
-
可能包含 Shell 的特殊字元(例如User_Input
)。要記住,| & < >
調用實際上先調用 Shell,之後讓 Shell 程式執行system
。如果我們不注意,攻擊者就可以執行其它程式,通過讓/bin/mail
是下面的字元串:User_Input
[email protected] ; rm -f /* ; /bin/sh
2.3 其它知名的漏洞模式
除了上面的輸入校驗漏洞,也有一些其他的知名漏洞模式。我們會在單獨的章節中讨論它們。這裡是這些模式的總結:
- 緩沖區溢出
- 競态條件
- 格式化字元串
2.4 雜項漏洞
有許多其他漏洞,并不易于歸納進上面讨論的任何分類。一些可能被歸納為更廣泛的“呼入椒鹽漏洞”,但是由于他們的獨特特性,我們在這裡單獨讨論它們。我們不能枚舉所有漏洞。我們隻能給出一些示例,來展示程式員在程式邏輯中的不同錯誤,并且展示這些錯誤如何變為漏洞。
-
漏洞:它在lpr
目錄下生成臨時檔案。檔案名稱應該是随機的,但是,由于僞随機數生成的錯誤,檔案名稱每一千次就會發生重複。這個程式是 Set-UID 程式。将可預測的檔案名稱連結到/tmp
會導緻/etc/passord
覆寫lpr
/etc/passord
-
漏洞:chsh
讓使用者輸入 Shell 程式的名稱s,并在chsh
中儲存輸入。/etc/passwd
并不會做清晰的檢查。程式假設使用者的輸入隻有一行,不幸的是,這個假設可以為假:使用者可以鍵入聯行輸入,其中第二行是類似chsh
的東西美麗如,使用者可以插入一個新的超級使用者賬戶(UID:0),不帶密碼。xyz::0:0::
-
漏洞sendmail
-
:(1)入境的郵件會添加在sendmail
。(2)如果/var/mail/wedu
的所有者不是 Wedu,/var/mail/wedu
會使用sendmail
将所有者修改為 Wedu。chown
- 你能利用它來讀取 Wedu 的郵件嗎?
- 你能利用它來給 Wedu 造成更大的損失嗎?
-