欢迎光临
我们一直在努力

Linux特殊权限SUID、SGID、Sticky Bit原理与实战

上一篇讲了 rwx 这套基本权限位。但 ls -l 里偶尔会冒出 rws、rwt 这种带字母 s 和 t 的位置,很多人第一次看到就懵了——这不是执行位吗,怎么变成小写字母了?这就是 Linux 的三个特殊权限位:SUID、SGID、Sticky Bit。它们在基本权限的"三位一组"之上再加一层,解决的是普通 rwx 解决不了的问题:让普通用户临时借程序属主的身份干活、让共享目录新建的文件自动继承组、让 /tmp 里人人能写却互删不了文件。

一、特殊权限在权限位里长什么样

特殊权限占权限数字的第四位(千位),和 rwx 一样可以用数字和符号两种方式表示:

特殊权限数字落在哪个位置ls -l 符号
SUID 4 属主的 x 位 s(有 x 时)/ S(无 x 时)
SGID 2 属组的 x 位 s(有 x 时)/ S(无 x 时)
Sticky Bit 1 其他人的 x 位 t(有 x 时)/ T(无 x 时)

注意大小写:小写 s/t 表示原 x 位存在,叠加特殊权限;大写 S/T 表示原 x 位是空的,特殊权限加上去但执行位没开——后者通常是配置错误。

先看两个现成的例子,系统自带的:

ls -l /usr/bin/passwd /tmp

预期输出:

-rwsr-xr-x 1 root root 68156 Jul 1 2023 /usr/bin/passwd
drwxrwxrwt 10 root root 4096 Sep 16 10:30 /tmp

passwd 的属主是 root,属主权限里那个 s 就是 SUID;/tmp 其他人权限位上的 t 就是 Sticky Bit。

二、SUID:让执行者临时拥有属主身份

原理

正常情况下,一个进程的权限等于执行者的身份。但给可执行文件挂上 SUID 后,任何人运行它时,进程的 UID 会临时变成文件属主的 UID,而不是运行者自己的 UID。

最典型的例子就是 passwd。普通用户要改自己的密码,密码存在 /etc/shadow 里,而这个文件只有 root 能写:

ls -l /etc/shadow

预期输出:

-rw-r—– 1 root shadow 1234 Sep 16 09:00 /etc/shadow

普通用户直接改 shadow 肯定没权限。passwd 命令靠 SUID 让自己运行时临时变成 root,改完 shadow 再把权限降回来,整个过程对用户透明。

设置与取消

chmod u+s 文件名 # 加 SUID
chmod u-s 文件名 # 去掉
chmod 4755 文件名 # 数字法:千位 4

做个实验,看进程身份怎么变:

sudo chown root:root /tmp/checkid
sudo chmod 4755 /tmp/checkid
ls -l /tmp/checkid

预期输出:

-rwsr-xr-x 1 root root 1024 Sep 16 11:00 /tmp/checkid

普通用户 zhangsan 运行它,进程的有效 UID 会变成 0(root),尽管启动者是 1001。

⚠️ 安全风险

SUID 是一把双刃剑。任何被挂上 SUID 的可执行文件,都是提权攻击的潜在入口。攻击者找到一个有 SUID 的、能调用 shell 的程序(比如旧版 find、nmap –interactive、vim),就能直接拿到 root shell。

运维上两件事要做:

  • 不要随便给脚本挂 SUID。bash、python 这类解释器会忽略脚本文件上的 SUID(安全设计),你挂了也没用,反而让人误以为生效。
  • 定期扫一遍系统里的 SUID 文件,确认没有多余的:sudo find / -perm -4000 -type f 2>/dev/null

    预期输出(节选):/usr/bin/sudo
    /usr/bin/passwd
    /usr/bin/su
    /usr/bin/mount
    /usr/bin/umount

    这些是系统正常的。如果业务目录里冒出来一个你不认识的 SUID 文件,就要查了。

  • 三、SGID:让共享目录继承组,让程序继承属组身份

    SGID 有两个完全不同的作用,看它挂在文件上还是目录上。

    挂在可执行文件上

    和 SUID 类似,只不过变的是组 ID:运行进程时,有效 GID 变成文件属组的 GID。实际用得很少,知道有这回事就行。

    挂在目录上(重点)

    这是共享目录的标准做法。给一个目录挂上 SGID 后,任何人在这个目录里新建的文件/子目录,属组都会自动继承目录的属组,而不是新建者自己的主组。

    场景:开发组共用 /data/dev,希望所有人往里建的文件组都是 developers,互相能改。

    sudo groupadd developers
    sudo chown root:developers /data/dev
    sudo chmod 2775 /data/dev # 千位 2 = SGID
    ls -ld /data/dev

    预期输出:

    drwxrwsr-x 2 root developers 4096 Sep 16 11:10 /data/dev

    注意属组权限位上的 s。现在 zhangsan 和 lisi 都把自己加进 developers 组,往里建文件:

    sudo su – zhangsan
    touch /data/dev/zhangsan_note.txt
    ls -l /data/dev/

    预期输出:

    -rw-rw-r– 1 zhangsan developers 0 Sep 16 11:12 zhangsan_note.txt

    文件的属组自动是 developers,而不是 zhangsan 的私有组。lisi 再建文件也是同一个组,配合 g+w,两人互相能改——团队共享目录的标准配方就是 chgrp + chmod 2775 + umask 002。

    设置与取消

    chmod g+s 目录 # 加 SGID
    chmod g-s 目录 # 去掉
    chmod 2755 目录 # 数字法

    四、Sticky Bit:/tmp 人人能写但互删不了

    问题

    回到开头那个矛盾:/tmp 要所有人可写(o+w),否则大家没法往临时目录里放东西。但如果只是普通的 0777,任何用户都能删掉别人的临时文件——因为删除文件看的是目录的 w 权限,不是文件本身的权限。

    Sticky Bit 就是来补这个漏洞的:给目录挂上 Sticky Bit 后,里面的文件只有属主(或 root)能删/改名,其他人就算对目录有 w 也不行。

    设置与取消

    chmod o+t 目录 # 加 Sticky Bit
    chmod o-t 目录 # 去掉
    chmod 1777 目录 # 数字法:千位 1

    看 /tmp:

    ls -ld /tmp

    预期输出:

    drwxrwxrwt 10 root root 4096 Sep 16 10:30 /tmp

    末尾的 t 就是 Sticky Bit。zhangsan 往 /tmp 放个文件,lisi 就算能进 /tmp,也删不掉它——只能删自己建的。

    什么时候该用

    凡是"多人共享、人人可写"的目录,除了 /tmp,还有 FTP 上传区、共享上传目录,都建议挂 Sticky Bit。忘了挂,迟早出事故。

    五、三个特殊权限速查表

    权限数字作用对象实际用途
    SUID 4 可执行文件 普通用户临时借属主身份运行(passwd、sudo)
    SGID 2 目录 新建文件自动继承目录属组(团队共享目录)
    SGID 2 可执行文件 临时借属组身份(少见)
    Sticky Bit 1 目录 共享目录里只能删自己的文件(/tmp)

    chmod 的四位数字从左到右就是 SUID SGID Sticky 基本权限,比如 4755、2755、1777。

    ⚠️ 常见错误

  • 看到大写 S/T 以为成功了:-rwsr-xr-x 和 -rwSr-xr-x 不一样。大写表示 x 位没开,SUID 形同虚设。设置后用 ls -l 确认是小写。
  • 把 SUID 挂在目录上:SUID 对目录无效,别费那个劲。目录要用的是 SGID 和 Sticky Bit。
  • 业务目录随便挂 SUID:曾经有人为了让某个日志程序能写 /var/log,把它挂了 SUID 给 root,结果这个程序又能调用 system(),等于送了一个 root shell。原则是:能用文件权限解决就别上 SUID,必须用也要挑不调用 shell、不读用户输入的静态编译程序。
  • 六、知识扩展:SUID 提权背后的内核机制

    SUID 之所以能工作,是因为 Linux 把"身份"拆成了两套:实际 ID(real ID) 和有效 ID(effective ID)。

    • 实际 ID:你是谁,记录在进程的 uid 字段,来自登录账号。
    • 有效 ID:内核做权限检查时实际参考的那个 ID,记录在 euid。

    平时两者相等。SUID 程序启动时,内核把 euid 设成文件属主的 uid,于是文件读写、capability 检查都按 root 算。程序结束后退出,这个提升不残留。

    passwd 正是利用这一点:它本身 setuid root,打开 shadow 写入新密码,然后立刻用 setuid(getuid()) 把自己降回普通用户身份再去做其他事。这种"用完就降权"的写法是安全编程的基本要求——只在需要 root 的那一小段持有 root。

    反过来,安全扫描工具查 SUID 提权漏洞,本质上就是在枚举:哪些 SUID 程序的 euid=0 阶段能被诱导去执行攻击者指定的命令(比如传一个 –exec 参数)。掌握了 real/effective 这层模型,看 Privilege Escalation 类文章时就不会被一堆名词绕晕。

    赞(0)
    未经允许不得转载:171主机测评 » Linux特殊权限SUID、SGID、Sticky Bit原理与实战
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址