Security system()与execve()的比较
和都可用于在程序内执行另一个命令。为什么在SETUID程序中,Security system()与execve()的比较,security,exec,elevated-privileges,setuid,Security,Exec,Elevated Privileges,Setuid,和都可用于在程序内执行另一个命令。为什么在SETUID程序中,system()是危险的,而execve()是安全的?system()和execve()的工作方式不同system()将始终调用shell,此shell将作为单独的进程执行命令(这就是为什么在使用system()时可以在命令行中使用通配符和其他shell工具的原因) execve()(以及exec()系列中的其他函数)将当前进程替换为直接生成的进程(除非出现故障,execve()函数不会返回)。实际上,system()实现应该使用一系
system()
是危险的,而execve()
是安全的?system()
和execve()
的工作方式不同system()
将始终调用shell,此shell将作为单独的进程执行命令(这就是为什么在使用system()
时可以在命令行中使用通配符和其他shell工具的原因)
execve()
(以及exec()
系列中的其他函数)将当前进程替换为直接生成的进程(除非出现故障,execve()
函数不会返回)。实际上,system()
实现应该使用一系列的fork()
、execve()
和wait()
调用来执行其功能
当然,这两者都是危险的,这取决于进程具有root权限时执行的操作system()
,但是,由于它使用了额外的shell“层”,在调用根shell时会打开房间安全漏洞,就像在您的问题中一样(即,进程具有suid位)。将调用shell()以执行作为参数发送的命令。system
的问题,因为shell行为取决于运行命令的用户。一个小例子:
创建文件test.c:
#include <stdio.h>
int main(void) {
if (system ("ls") != 0)
printf("Error!");
return 0;
}
在当前目录中创建名为ls
的脚本:
$ cat > ls
#!/bin/sh
/bin/sh
$ chmod +x ls
现在:
哎呀,你有一个具有root权限的shell
不调用shell。它执行作为第一个参数传递给它的程序。程序必须是二进制可执行文件或以第行开头的脚本。除了
system()
所述的安全问题外,派生进程继承主程序的环境。当使用suid
时,这可能会非常有问题,例如当调用进程设置LD\u LIBRARY\u PATH
-环境变量时
使用exec()
-系列,调用程序可以在调用exec()
之前将环境设置为被调用程序所需的(和安全的)环境
当然,
system()
调用的shell本身可能存在安全问题。因此,在使用execve()时。。您提到它取代了当前流程。。进程是否仍为setuid?是。由execve启动的“新”进程继承被替换进程的许多属性,如文件描述符、套接字等,有效的uid就是其中之一,但在执行execve期间,uid会发生变化,比如execve参数所指的可执行文件设置了suid位。在这种情况下,uid被更改为文件系统中定义的文件所有者。不说system()
是没有问题的,但上述问题不是可以通过在二进制可执行文件中使用绝对路径来解决的吗?@JoelDavis,不,您至少需要清除整个环境,为几个环境变量(PATH,HOME…)提供合理的默认值,如果需要,在消毒后保存一些环境变量(术语、显示、语言…),确保fds 0、1、2处于打开状态。。。基本上做sudo做的事。即使那样,我也不会去那里。如果可以避免的话,不要在特权升级上下文中调用shell。请注意,ls
可以在其环境中做一些奇特的事情,因此即使没有system()
,您也应该清理环境。使用setuids时,您希望最小化作为root用户所做的操作(通常不执行命令)。@JoelDavis:不,即使使用完整路径,您仍然有问题。如果使用/bin/ls
,用户可以将/
添加到$IFS
,从而导致外壳拆分/bin/ls
到bin
和ls
。现在,当前目录中名为bin
的可执行文件可以做与我的回答中的ls
相同的事情。谢谢你们。这实际上是一个非常有趣的答案。当非root用户运行setuid程序时,环境变量LD_LIBRARY_PATH将被忽略,除非实际uid也是0。
$ 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