前言
Linux对于权限的管理,系统权限只有root才有,对于普通用户只有一些有限的权限;而对于普通用户如果想进行一些权限以外的操作,之前主要有两种方法:一是通过sudo提权;二是通过SUID[1],让普通用户对设有SUID的文件具有执行权限,当用户执行此文件时,会用文件的拥有者的权限执行,比如常用的命令passwd
,修改用户的密码是需要root权限的,但是普通用户却可以使用,这是因为/usr/bin/passwd
被设置了SUID,该文件的拥有者是root,所以普通用户可以使用并执行。然而SUID却带来了安全隐患,因为本身需要一部分特权,但是却拥有了root的全部权限,所以为了对root权限进行更加细粒度的控制,Linux 引入了 capabilities
机制对 root 权限进行细粒度的控制,实现按需授权,从而减小系统的安全攻击面。本文主要总结 Capabilites 机制的基本概念和利用。
Linux Capabilities 是什么?
从内核 2.2 开始,Linux 将传统上与超级用户 root 关联的特权划分为不同的单元,称为Capabilites
。Capabilites 作为线程(Linux 并不真正区分进程和线程)的属性存在,每个单元可以独立启用和禁用。如此一来,权限检查的过程就变成了:在执行特权操作时,如果进程的有效身份不是 root,就去检查是否具有该特权操作所对应的 capabilites
,并以此决定是否可以进行该特权操作。比如要向进程发送信号(kill()),就得具有 capability CAP_KILL
;如果设置系统时间,就得具有 capability CAP_SYS_TIME
。
Linux中的capability是可以分配给进程、二进制文件、服务和用户等的特殊属性,它们可以允许它们拥有通常保留给root级行动的特定权限,Capabilities 可以在进程执行时赋予,也可以直接从父进程继承。所以理论上如果给 nginx 可执行文件赋予了 CAP_NET_BIND_SERVICE
,那么它就能以普通用户运行并监听在 80 端口上。
不同的Capabilities
线程 Capabilities
每一个线程,具有5个capabilities
集合,每一个集合使用 64 位掩码来表示,显示为 16 进制格式。五种 capabilities 集合类型,分别是:
-
CapInh: Inheritable capabilities
-
CapPrm: Permitted capabilities
-
CapEff: Effective capabilities
-
CapBnd: Bounding set
-
CapAmb: Ambient capabilities set
每个集合中都包含零个或多个 capabilities。这5个集合的具体含义如下:
-
CapEff(Effective)
: Effective代表进程目前正在使用的所有Capabilities(这是内核用于权限检查的实际capabilities集)。对于文件capabilities来说,Effective实际上是一个单一的位,表示在运行二进制文件时,Permitted
的Capabilities是否会被移到Effective
集。这使得那些没有capabilities的二进制文件有可能在不发出特殊系统调用的情况下使用文件Capabilities。 -
CapPrm(Permitted)
: 这是一个capabilities的超集,线程可以将其添加到线程允许的或线程可继承的集合中。线程可以使用capset()
系统调用来管理Capabilities。它可以从任何集合中删除任何Capabilities,但只能向其线程Effective
和Inheritable
添加线程允许集合中的Capabilities。因此,它不能将任何Capabilities添加到其线程允许的集合中,除非它的线程有效集合中有CAP_SETPCAP
。 -
CapInh(Inheritable)
: 使用Inheritable
集可以指定允许从父进程继承的所有Capabilities。这可以防止一个进程接收它不需要的任何Capabilities。这里需要说明一下,包含在该集合中的 capabilities 并不会自动继承给新的可执行文件,即不会添加到新线程的Effective
集合中,它只会影响新线程的Permitted
集合。 -
CapBnd(Bounding)
:Bounding
集合是Inheritable
集合的超集,可以限制一个进程可能收到的Capabilities。在Inheritable
和Permitted
集中,只有存在于Bounding
集中的Capabilities才被允许。 -
CapAmb(Ambient)
: Linux 4.3 内核新增了一个 capabilities 集合叫Ambient
,用来弥补Inheritable
的不足。Ambient
集适用于所有没有文件Capabilities的非SUID二进制文件。它在execve()
时保留了Capabilities。然而,并不是所有在Ambient集的Capabilities都会被保留,因为它们会被丢弃,以防它们不在Inheritable
或Permitted
集中出现。这个集合在 execve 调用时被保留。Ambient 的好处显而易见,举个例子,如果你将CAP_NET_ADMIN
添加到当前进程的 Ambient 集合中,它便可以通过fork()
和execve()
调用shell
脚本来执行网络管理任务,因为CAP_NET_ADMIN
会自动继承下去。
要查看某个特定进程的capabilities,可以使用/proc
目录下的状态文件。
对于所有正在运行的进程,capabilities信息是按线程维护的,对于文件系统中的二进制文件,它被存储在扩展属性中。
可以在/usr/include/linux/capability.h
中找到定义的Capabilities。可以在cat /proc/self/status
或capsh --print
中找到当前进程的capabilities,在/proc/<pid>/status
中找到其他用户的capabilities。
cat /proc/<pid>/status | grep Cap
# 查看当前进程的capabilities
cat /proc/$$/status | grep Cap
这是一个典型的root
进程所拥有的capabilities。
-
capsh
但是这种方式获得的信息无法阅读,我们需要使用 capsh
命令把它们转义为可读的格式:
capsh --decode=0000003fffffffff