从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)
。
请参阅setuid
, seteuid
, getuid
和geteuid
的man
页,以了解真实有效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包装器。