Linux SetUID(SUID)文件特殊权限用法详解

在 Linux 系统中我们已经学习过 r(读)、w(写)、 x(执行)这三种文件普通权限,但是我们在査询系统文件权限时会发现出现了一些其他权限字母,比如:
[root@localhost ~]#ll /usr/bin/passwd
-rwsr-xr-x 1 root root 25980 2月22 2012/usr/bin/passwd

大家发现了吗?在属主本来应该写 x(执行)权限的位置出现了一个小写 s,这是什么权限?我们把这种权限称作 SetUID 权限,也叫作 SUID 的特殊权限。这种权限有什么作用呢?

我们知道,在 Linux 系统中,每个普通用户都可以更改自己的密码,这是合理的设置。问题是,普通用户的信息保存在 /etc/passwd 文件中,用户的密码实际保存在 /etc/shadow 文件中,也就是说,普通用户在更改自己的密码时修改了 /etc/shadow 文件中的加密密码,但是,看下面的代码:
[root@localhost ~]#ll /etc/passwd
-rw-r–r-- 1 root root 1728 1月19 04:20 /etc/passwd
[root@localhost ~]#ll /etc/shadow
---------- 1 root root 1373 1月19 04:21 /etc/shadow

/etc/passwd 文件的权限是 644,意味着只有超级用户 root 可以读/写,普通用户只有只读权限。/etc/shadow 文件的权限是 000,也就是没有任何权限。这意味着只有超级用户可以读取文件内容,并且可以强制修改文件内容;而普通用户没有任何针对 /etc/shadow 文件的权限。

换句话说,普通用户对这两个文件其实都是没有写权限的,那为什么普通用户可以修改自己的权限呢?

其实,普通用户可以修改自己的密码的秘密不在于 /etc/passwd 和 /etc/shadow 这两个文件,而在于 passwd 命令。我们再来看看 passwd 命令的权限:
[root@localhost ~]#ll /usr/bin/passwd
-rwsr-xr-x.1 root root 25980 2月22 2012 /usr/bin/passwd

passwd 命令拥有特殊权限 SetUID,也就是在属主的权限位的执行权限上是 s。可以这样来理解它:当一个具有执行权限的文件设置 SetUID 权限后,用户在执行这个文件时将以文件所有者的身份来执行。passwd 命令拥有 SetUID 权限,所有者为 root(Linux 中的命令默认所有者都是 root),也就是说,当普通用户使用 passwd 命令更改自己的密码的时候,实际上是在用 passwd 命令所有者 root 的身份在执行 passwd 命令,root 当然可以将密码写入 /etc/shadow 文件,所以普通用户也可以修改 /etc/shadow 文件,命令执行完成后,该身份也随之消失。

SetUID 的功能可以这样理解:
只有可以执行的二进制程序才能设定 SetUID 权限。
命令执行者要对该程序拥有 x(执行)权限。
命令执行者在执行该程序时获得该程序文件属主的割分(在执行程序的过程中变为文件的属主)。
SetUID 权限只在该程序执行过程中有效,也就是说身份改变只在程序执行过程中有效。

举个例子,有一个用户 lamp,她可以修改自己的权限,因为 passwd 命令拥有 SetUID 权限;但是她不能査看 /etc/shadow 文件的内容,因为査看文件的命令(如 cat)没有 SetUID 权限。命令如下:
[root@localhost ~]# su - lamp
[lamp@localhost ~]$ passwd
更改用户lamp的密码。
为lamp更改STRESS密码。
(当前)UNIX密码:
#输入旧密码
新的密码:
#输入新密码
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新
#lamp可以修改自己的密码
[lamp@localhost ~]$ cat /etc/shadow
cat:/etc/shadow:权限不够
#但是不能査看/etc/shadow文件的内容

我们画一张示意图来理解上述过程,如图 1 所示。

图 1 SetUID示意图

从示意图中可以知道:
passwd 是系统命令,可以执行,所以可以赋予 SetUID 权限。
lamp 用户对 passwd 命令拥有 x(执行)权限。
lamp 用户在执行 passwd 命令的过程中,会暂时切换为 root 身份,所以可以修改 /etc/shadow 文件。
命令结束,lamp 用户切换回自己的身份。

cat 命令没有 SetUID 权限,所以就使用 lamp 用户身份去访问 /etc/shadow 文件,当然没有相应权限了。

如果把 /usr/bin/passwd 命令的 SetUID 权限取消,普通用户是不是就不能修改自己的密码了呢?试试吧:
[root@localhost ~]# chmod u-s /usr/bin/passwd
#属主取消SetUID权限
[root@localhost ~]# ll /usr/bin/passwd
-rwxr-xr-x.1 root root 25980 2月22 2012/usr/bin/passwd
[root@localhost ~]# su -lamp
[lamp@localhost ~]$ passwd
更改用户lamp的密码。
为lamp更改STRESS密码。
(当前)UNIX密码:
#看起来没有什么问题
新的密码:
重新输入新的密码:
passwd:鉴定令牌操作错误
#但是最后密码没有生效

这个实验可以说明 SetUID 的作用了吧,不过记得一定要把 /usr/bin/passwd 命令的 SetUID 权限加回来。
危险的SetUID
我们刚刚的实验是把系统命令本身拥有的 SetUID 权限取消,这样会导致命令本身可以执行的功能失效。但是如果我们给默认没有 SetUID 权限的系统命令赋予了 SetUID 权限,那又会出现什么情况呢?那样的话系统就会出现重大安全隐患,这种操作一定要随意执行。

手工赋予 SetUID 权限真有这么恐怖吗?我们试试常见的命令 vim 赋予 SetUID 权限,看看会发生什么事情。
[root@localhost ~]# chmod u+s /usr/bin/vim
[root@localhost ~]# ll /usr/bin/vim
-rwsr-xr-x 1 root root 1847752 4月5 2012 /usr/bin/vim

当 vim 命令拥有了 SetUID 权限后,任何普通用户在使用 vim 命令时,都会暂时获得 root 的身份和权限,很多普通用户本身不能査看和修改的文件马上就可以査看了,包括 /etc/passwdf 和 /etc/shadow 这两个重要的用户信息文件,这样我就可以轻易地把自己的 UID 改为 0,升级为超级用户了。如果我修改了系统重要的启动文件,比如 /etc/inittab 或 /etc/fstab,就可以轻易地导致系统瘫痪。

其实任何只有管理员可以执行的命令,如果被赋予了 SetUID 权限,那么后果都是灾难性的。大家可以想象普通用户可以随时重启服务器、随时关闭看得不顺眼的服务、随时添加其他普通用户的服务器是什么样子的吗?

所以,SetUID 权限不能随便设置,同时要防止黑客的恶意修改。怎样避免 SetUID 的不安全影响?有几点建议:

关键目录应严格控制写权限,比如"/" "/usr"等。
用户的密码设置要严格遵守密码规范。
对系统中默认应该有 SetUID 权限的文件制作一张列表,定时检査有没有列表之外的文件被设置了 SetUID 权限。

其他几点都很好理解,可是应该如何建立 SetUID 权限文件列表,并定时检査呢?我来写写这个脚本,大家可以作为参考。

首先,在服务器第一次安装完成后,马上査找系统中所有拥有 SetUID 和 SetGID 权限的文件,把它们记录下来,作为扫描的参考模板。如果某次扫描的结果和本次保存下来的模板不一致,就说明有文件被修改了 SetUID 和 SetGID 权限。命令如下:
[root@localhost ~]# find / -perm -4000 -o -perm -2000 > /root/suid.list
#-perm安装权限査找。-4000对应的是SetUID权限,-2000对应的是SetGID权限
#-o是逻辑或"or"的意思。并把命令搜索的结果放在/root/suid.list文件中
接下来,只要定时扫描系统,然后和模板文件比对就可以了。脚本如下:
[root@localhost ~]#vi suidcheck.sh
#!/bin/bash

Author:shenchao (E-mail:[email protected])

find / -perm -4000 -o -perm -2000 > /tmp/setuid.check
#搜索系统中所有拥有SetUID和SetGID权限的文件,并保存到临时目录中
for i in $(cat /tmp/setuid.check)
#循环,每次循环都取出临时文件中的文件名
do
grep KaTeX parse error: Expected 'EOF', got '#' at position 31: …st > /dev/null #̲比对这个文件名是否在模板文件中…?"!=“o”]
#检测测上一条命令的返回值,如果不为0,则证明上一条命令报错
then
echo "KaTeX parse error: Expected group after '_' at position 40: …>/root/suid_log_̲(date +%F)
#如果文件名不在模板文件中,则输出错误信息,并把报错写入日志中
fi
done
rm -rf/tmp/setuid.check
#删除临时文件
[root@localhost ~]# chmod u+s /bin/vi
#手工给vi加入SetUID权限
[root@localhost ~]# ./suidcheck.sh
#执行检测脚本
[root@localhost ~]# cat suid_log_2013-01-20
/bin/vi isn’t in listfile!
#报错了,vi不在模板文件中。代表vi被修改了SetUID权限

这个脚本成功的关键在于模板文件是否正常。所以一定要安装完系统就马上建立模板文件,并保证模板文件的安全。

注意,除非特殊情况,否则不要手工修改 SetUID 和 SetGID 权限,这样做非常不安全。而且就算我们做实验修改了 SetUID 和 SetGID 权限,也要马上修改回来,以免造成安全隐患。

猜你喜欢

转载自blog.csdn.net/zyy1659949090/article/details/88176511