如何使我设置好setuid的shell脚本运行起来呢?[这个说起来有点复杂,但绝对是一个经常被提及的问题。感谢Maarten Litmaath为此做出的解答,同时感谢下面提到的“indir”项目组。]
我们首先假设你在一台UNIX的机器(例如:4.3BSD或者SunOS)旁边,并且了解所谓的“可执行shell脚本”。 此类脚本必须以“#!/bin/sh”开头,它之所以被称为“可执行的”,是因为它以一个所谓的“幻数”开头,来表明它就像一个真的可执行文件(二进制文件)一样是可执行的。
我们这里的“幻数”就是“#!”,可能后面还会带上一个初始化选项,如:#!/bin/sed -f,操作系统将对余下的脚本代码解释执行。假设该脚本文件叫做“foo”,存放在/bin中,然后你输入:foo arg1 arg2 arg3,操作系统将会加载脚本内的命令,使其变成这种形式:/bin/sed -f /bin/foo arg1 arg2 arg3。但是这两种执行方式有一点不同:如果对“foo”设置了setuid位,它将在执行过程中升级权限;如果你直接敲入第二种命令,操作系统当然就只会按照/bin/sed的权限来执行命令。
OK, 但是如果我的shell脚本不是以“#!”开头的,或者我的操作系统不认识这个"幻数"怎么办呢?嗯,这样的话,如果shell尝试执行它,操作系统会返回一个错误提示,因为你的文件是以一个无效的"幻数"开头的。一旦收到这个提示,shell会假定这个文件是一个shell脚本文件,并做另一种尝试:/bin/sh/ shell_script arguments。但是我们已经看到了“shell_script”虽然被置setuid位,却依然没有任何效果!
好了,那么关于setuid的shell脚本在安全威胁方面有什么要注意的么?现在假设该脚本叫做“/etc/setuid_script”,以“#!/bin/sh”开头。我们来看看如果我们执行这条命令会如何:
$ cd /tmp
$ ln /etc/setuid_script -i
$ PATH=.
$ -i
我们知道最后一条命令会被转换成 /bin/sh -i。但是这条命令会给我们一个交互的shell,setuid将权限升级为脚本文件的拥有者!幸运的是,这个安全漏洞能够很容易的被关掉,只要把第一行做如下改动即可:#!/bin/sh - 。选项表最后的‘-’用来标记出下一个参数:‘-i’将被当作这些命令所在的文件的名字,它原本就该如此,呵呵。当然还有更加严重一些的问题:
$ cd /tmp
$ ln /etc/setuid_script temp
$ nice -20 temp &
$ mv my_script temp
第三条命令会被转换成:nice -20 /bin/sh - temp 。由于这条命令运行如此之慢,第四条命令可能会在‘temp’被shell打开之前把‘temp’替换成‘my_script’!
有4中方法可以解决这个安全漏洞:
1)让操作系统以一种不同的、安全的方式运行setuid的脚本文件。 - System V R4以及4.4BSD使用 /dev/fd 驱动给解释器传递一个关于脚本的描述文件。
2)让脚本在前端被直接解释执行,那样能够保证在真正的解释器开始执行之前不会出问题。如果你使用comp.sources.unix的“indir”程序,那么setuid脚本看上去将会是这样:#!/bin/indir -u #?/bin/sh /etc/setuid_script
3)做一个二进制包:一个真正可执行的setuid文件,它唯一的任务就是将脚本作为一个参数,直接启动解释器执行它。
4)做一个普通的‘setuid脚本服务器’,尝试将请求的服务定位到一个有效的脚本上,那样就能保证使用正确的参数执行正确的脚本了。
现在我们可以保证是正确的文件送入解释器了,还有其他的风险么?当然!别玩了你一定要给shell脚本在PATH变量中显式的设置一个安全的路径。你能猜出为什么这样做吗? 同样如果设置不当,可能会有一个IFS变量带来麻烦。其他的环境变量的安全性也许会降低,例如 e.g.SHELL... 进一步的,你必须保证脚本中的命令不能允许进入交互式询问shell退出的情形!然后还有一个umask被设置的有些奇怪,等等。你应该意识到一个setuid脚本会引起它所执行的命令会带来的所有的麻烦! 最后,我们得到一个结论,setuid shell脚本是一个极度危险的东西!你最好写一个C程序来代替它!
Linux权限360度赤裸裸华丽丽大曝光连载之二:深入理解SetUID:http://www.linuxdiyf.com/linux/7078.html