从setuid root C程序调用脚本 – 脚本不以root身份运行

我需要以root身份运行bash脚本(无密码sudo或su不可行),因为你无法在Linux中设置脚本,我想从可执行文件中调用它并使其成为 setuid:

$ cat wrapper.c int main(void) { system("/bin/bash ./should_run_as_root.sh"); } $ gcc -o wrapper wrapper.c $ sudo chown root wrapper $ sudo chmod ug+s wrapper $ ll wrapper -rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper $ 

这有效 – 就像正确运行脚本一样 – 但脚本以执行“./wrapper”的用户身份运行。

为什么? 以及如何正确实现这一点?

谢谢!

由于可执行文件上的suid位只更改了可执行文件将运行的有效UID(EUID),而不是getuid()返回的实际UID(RUID),以及对suid解释脚本的限制(任何以“ #! “),在这种情况下,像bash作为额外安全措施的一些shell会将EUID设置回RUID,在执行脚本之前,您需要在C代码中使用调用setuid(0)

请参阅setuidseteuidgetuidgeteuidman页,以了解真实有效UID的确切语义。

警告 )当然,这是适当的一点,在许多Unix系统,shell和解释器中对suid脚本的限制是有原因的,即如果脚本不是非常小心清理它的输入和执行时的环境状态,它们是危险的,可以被利用来进行安全升级。 这样做时要非常小心。 尽可能严格地设置对脚本和包装器的访问权限,只允许执行此特定脚本,并在启动脚本之前清除C程序中的环境,设置PATH等环境变量以准确包含是正确的顺序是必要的,没有可写给他人的目录。

这里要注意的另一件事是这里的限制来自bash而不是* nix系统本身。 Bash实际上对SUID脚本进行了validation,只能使用EUID root执行它们。 如果你选择较旧的贝壳,你通常会得到你想要的东西。 例如,sh不进行这种validation:

 $ cat wrapper.c int main(void) { system("/bin/sh -c whoami"); } $ ls -l wrapper -rwsr-sr-x 1 root users 8887 Feb 17 14:15 wrapper $ ./wrapper root 

用bash:

 $ cat wrapper.c int main(void) { system("/bin/bash -c whoami"); } $ ls -l wrapper -rwsr-sr-x 1 root users 8887 Feb 17 14:18 wrapper $ ./wrapper skinp 

尽管如此,汤姆的答案通常是为SUID根程序制作包装器的方法

在脚本中添加setuid(0)并对其进行编译。 在此之后它会工作。

 $ cat wrapper.c int main(void) { setuid(0); system("/bin/bash ./should_run_as_root.sh"); } $ gcc -o wrapper wrapper.c $ sudo chown root wrapper $ sudo chmod ug+s wrapper $ ll wrapper -rwsr-sr-x 1 root users 6667 2009-02-17 11:11 wrapper $ 

这些例子非常不安全,允许任何拥有两点知识的人运行他们想要的任何程序作为setuid用户。

除非您首先清理环境,否则永远不要通过shell,此处显示的大多数示例都容易在运行之前设置IFS和PATH。

为什么sudo不可行? 它避免了肆虐的安全漏洞,例如:

 bash-3.2$ cat test #!/bin/bash echo ima shell script durp durp bash-3.2$ chmod +x test bash-3.2$ ./test heh heh bash-3.2$ 

由于环境没有得到适当的消毒,例如在这种情况下:

 export echo='() { builtin echo heh heh; }' 

sudo清理这个案例,也许还有其他边缘案例和陷阱,这些案例和陷阱很难不写入自定义suid包装器。