system()vs execve()

时间:2014-12-12 10:25:03

标签: security exec elevated-privileges setuid

system()execve()都可以用来在程序中执行另一个命令。为什么在set-UID程序中,system()是危险的,而execve()是安全的?

3 个答案:

答案 0 :(得分:16)

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行开头的脚本。

答案 1 :(得分:11)

system()execve()以不同的方式工作。 system()将始终调用shell,并且此shell将作为单独的进程执行该命令(这就是为什么在使用system()时可以在命令行中使用通配符和其他shell工具的原因。)

execve()(以及exec()系列中的其他函数)将当前进程替换为直接生成的进程(execve()函数不会返回,除非是大小写失败)。实际上system()实现应该使用一系列fork()execve()wait()调用来执行其功能。

当然,两者都很危险,具体取决于进程具有root权限时正在执行的操作。但是,system()会带来一些额外的危险,因为额外的shell&#34;层&#34;它使用那个打开房间安全漏洞,因为它调用根shell,就像你的问题一样(即,进程有suid位)。

答案 2 :(得分:1)

除了system()提到的安全问题之外,衍生进程还继承了主程序的环境。使用suid时可能会出现问题,例如,当调用进程设置LD_LIBRARY_PATH - 环境变量时。

使用exec() - 系列,调用程序可以在调用exec()之前将环境设置为所调用程序所需的(并且安全)。

当然,system()调用的shell本身也存在安全问题。