system()
和execve()
都可以用來在程序中執行另一個命令。爲什麼在設置UID程序中,system()
是危險的,而execve()
是安全的?system()vs execve()
回答
system()
和execve()
以不同的方式工作。 system()
將始終調用shell,並且該shell將作爲單獨的進程執行該命令(這就是爲什麼當您使用system()
時可以在命令行中使用通配符和其他shell工具的原因)。
execve()
(和exec()
家族中的其他函數)將當前進程替換爲直接生成的進程(execve()
函數不會返回,除非發生故障)。實際上,system()
實現應該使用一系列調用fork()
,execve()
和wait()
來執行其功能。
當然,這兩者都是危險的,具體取決於當進程具有root權限時正在執行的內容。但是,由於它使用了額外的shell「層」,因爲它會在您的問題(即進程具有suid位)的情況下調用根shell時打開機房安全漏洞,所以它會帶來一些額外的危險。
system將調用shell(sh)執行作爲參數發送的命令。 system
的問題,因爲shell行爲取決於運行該命令的用戶。一個小例子:
創建文件test.c
:
#include <stdio.h>
int main(void) {
if (system ("ls") != 0)
printf("Error!");
return 0;
}
然後:
$ gcc test.c -o test
$ sudo chown root:root test
$ sudo chmod +s test
$ ls -l test
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test
創建在當前目錄中名爲ls
腳本:
$ cat > ls
#!/bin/sh
/bin/sh
$ chmod +x ls
現在:
$ PATH=. ./test
# /usr/bin/id
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root),
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner),
110(bluetooth),111(netdev),999(docker),1000(cuonglm)
# /usr/bin/whoami
root
糟糕,你有一個擁有root權限的shell。
execve不調用shell。它執行傳遞給它的程序作爲第一個參數。該程序必須是二進制可執行文件或腳本以shebang行開頭。
不說'system()'沒有問題,但不會通過在二進制可執行文件中使用絕對路徑來解決上述問題嗎? – Bratchley 2014-12-12 12:07:25
@JoelDavis,不,你至少需要清除整個環境,給一些envvars(PATH,HOME ...)提供理智的默認值,如果需要,在消毒後保存一些env vars(TERM,DISPLAY,LANG。 ..)確保fds 0,1,2是開放的...基本上做什麼sudo。即使那樣,我也不會去那裏。如果可以避免,請不要在特權升級上下文中調用shell。請注意,'ls'可以用它的環境做一些奇特的事情,所以即使沒有'system()',你也應該清理環境。在使用setuids時,您希望儘量減少以root身份執行的操作(通常不執行命令)。 – 2014-12-12 14:07:52
@JoelDavis:不,即使使用完整路徑,仍然存在問題。如果你使用'/ bin/ls',用戶可以將'/'添加到'$ IFS',導致shell將'/ bin/ls'分割爲'bin'和'ls'。現在,在我的答案中,當前目錄中名爲'bin'的可執行文件可以與'ls'做同樣的事情。 – cuonglm 2014-12-12 16:39:12
除了提及的system()
安全問題之外,產生的進程繼承了主程序的環境。當使用suid
時,例如當調用進程設置LD_LIBRARY_PATH
-環境變量時,這可能是非常有問題的。
與exec()
-家庭調用程序可以調用exec()
之前調用程序所需的(和安全)所需的環境設置。
當然,由system()
調用的shell本身可能有安全問題。
- 1. Python:MemoryError vs OverflowError vs instant-system-freeze
- 2. 從VS Professional轉移到VS Team System
- 3. execve error當調用execve(man,args,env)
- 4. execve:將execve調用轉換爲叉
- 5. su vs system-app(關機/重啓-p)
- 6. Team System 2008和VS 2005代碼
- 7. libcurl庫VS使用system()調用捲曲
- 8. 的execve調用
- 9. execve()做什麼?
- 10. 與execve的
- 11. linux_binprm中的execve()
- 12. 持續集成 - 開始之路:CruiseControl.NET vs TeamCity vs Visual Studio Team System
- 13. 「rvm rubygems current」vs「rvm update --system」vs「gem update rubygems-update」
- 14. execve與sed失敗
- 15. execve的源代碼()
- 16. 難以使用execve
- 17. execve的UNIX系統
- 18. fork和execve的問題
- 19. 調用execve()+更改PWD
- 20. 執行函數execve(unistd.h)
- 21. execve帶路徑搜索?
- 22. 的execve()的任何命令
- 23. fork和execve分段錯誤
- 24. 解析execve的命令行()
- 25. C和execve(3)參數
- 26. 在c(Linux)中複製execve?
- 27. execve的返回狀態
- 28. Shellcode:執行2 execve()調用
- 29. execve(「/ bin/sh」,0,0);在管道
- 30. 無法執行系統調用「execve」
所以,當使用execve()..你提到它取代當前進程..該進程仍然setuid? – Jake 2014-12-12 10:44:55
是的。由execve啓動的「新」進程繼承了被替換的一些屬性,例如filedescriptors,sockets等,而有效的uid就是其中之一,但是在執行execve期間uid會發生變化,比如如果execve參數指向的可執行文件已設置suid位。在這種情況下,uid會根據文件系統中的定義更改爲文件所有者。 – Marcelo 2014-12-12 10:54:17