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:将execve调用转换为叉
- 4. execve error当调用execve(man,args,env)
- 5. Team System 2008和VS 2005代码
- 6. su vs system-app(关机/重启-p)
- 7. linux_binprm中的execve()
- 8. 的execve调用
- 9. execve()做什么?
- 10. 持续集成 - 开始之路:CruiseControl.NET vs TeamCity vs Visual Studio Team System
- 11. execve的源代码()
- 12. execve与sed失败
- 13. execve的UNIX系统
- 14. 难以使用execve
- 15. execve的返回状态
- 16. execve(“/ bin/sh”,0,0);在管道
- 17. 解析execve的命令行()
- 18. 调用execve()+更改PWD
- 19. Shellcode:执行2 execve()调用
- 20. 的execve()的任何命令
- 21. Win64 vs System V ABI(x86_64):Win64跳过注册?
- 22. PHP的system()函数调用IIS7 CGI VS阿帕奇
- 23. 使用`system`有一长串VS多个参数
- 24. 从PHP Web应用调用C++库:system()vs SWIG PHP extension?
- 25. Scrapping RSS scraping system
- 26. 'System :: String ^'到'LPCWSTR'
- 27. Matlab,system和exe
- 28. Magento SYSTEM备份
- 29. Httpd +/bin/false == system()?
- 30. Point System - localStorage
所以,当使用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