Linux 功能的优势

作者:Michael Bacarella

如今,安全是一个常见的讨论话题,而且理由充分。随着世界变得更加网络化,安全变得越来越重要。像所有优秀的系统一样,Linux 也在不断发展,以应对日益重要的安全问题。

安全的一个方面是用户权限。UNIX 风格的用户权限分为两种:用户和 root。普通用户绝对无能为力;他们无法修改任何进程或文件,除了他们自己的。硬件和大多数网络规范的访问也被拒绝。另一方面,root 用户可以做任何事情,从修改所有进程和文件到拥有不受限制的网络和硬件访问权限。在某些情况下,root 用户甚至可以物理损坏硬件。

有时需要一种折衷方案。一个实用程序需要特殊的权限来执行其功能,但毋庸置疑的上帝般的 root 访问权限又显得过分。ping 实用程序被设置为 setuid root,仅仅是为了它可以发送和接收 ICMP 消息。危险在于,ping 可能会在其放弃 root 权限之前被利用,从而使攻击者获得您服务器的 root 访问权限。

幸运的是,现在存在这样一种折衷方案,它被称为 POSIX 功能。功能将系统访问划分为逻辑组,这些逻辑组可以单独授予或从不同的进程中移除。功能允许系统管理员微调进程允许执行的操作,这可能有助于他们显著降低系统的安全风险。最棒的是,您的系统已经支持它。如果您幸运的话,可能不需要任何补丁。

您的系统能够支持的所有功能的列表,可在 /usr/include/linux/capability.h 中找到,从 CAP_CHOWN 开始。它们都非常容易理解并且注释良好。功能检查散布在内核源代码中,grep 搜索它们可以带来一些有趣的午夜阅读。

每个功能只不过是位图中的一位。由于功能集中有 32 位,并且目前定义了 28 个集合,因此目前正在讨论如何扩展这个数字。一些纯粹主义者认为,添加额外的功能会过于令人困惑,而另一些人则认为应该有更多功能,甚至每个系统调用都应该有一个功能。时间和 Linus 最终将决定这个令人兴奋的功能如何发展。

Proc 接口

从内核 2.4.17 开始,文件 /proc/sys/kernel/cap-bound 包含一个 32 位整数,用于定义当前的全局功能集。全局功能集决定了系统上的每个进程允许执行的操作。如果从系统中剥夺了某个功能,则任何进程,甚至 root 进程,都无法重新获得它们。

例如,许多黑客的 rootkit(一组用于掩盖其活动并将后门安装到系统中的工具)将加载内核模块,以向系统管理员隐藏非法进程和文件。为了应对这种情况,管理员可以简单地从系统中删除 CAP_SYS_MODULE 功能,作为系统启动过程的最后一步。此步骤将阻止任何内核模块被加载或卸载。一旦某个功能被删除,就无法重新添加。必须重新启动系统(这意味着如果您删除了 CAP_SYS_BOOT 功能,则可能必须使用电源按钮)才能重新获得完整的功能集。

好吧,我撒谎了。有两种方法可以重新添加功能

  1. 理论上,init 可以重新添加功能;据我所知,没有实际的实现。这是为了方便支持功能的系统,以防 init 需要更改运行级别。

  2. 如果一个进程具有 CAP_SYS_RAWIO 功能,它可以通过 /dev/mem 修改内核内存。除其他外,它可以修改内核内存以授予自己所需的任何访问权限。删除 CAP_SYS_RAWIO,但请注意:删除 CAP_SYS_RAWIO 后,X 等程序很可能无法运行。

手动编辑 cap-bound 有点繁琐。幸运的是,您可以使用一个名为 lcap 的实用程序,它为 cap-bound 提供了更友好的界面。以下是如何删除 CAP_SYS_CHOWN 的方法

lcap CAP_SYS_CHOWN
完成后,将无法更改文件的所有者
chown nobody test.txt
chown: changing ownership of `test.txt':
       Operation not permitted
以下是如何删除除 CAP_SYS_BOOT、CAP_SYS_KILL 和 CAP_SYS_NICE 之外的所有功能
lcap -z CAP_SYS_BOOT CAP_SYS_KILL CAP_SYS_NICE
需要注意的一点:修改 cap-bound 仅限制未来进程的功能。好吧,不完全是未来的进程,而是任何调用 exec(2) 的进程(请参阅内核源文件 fs/exec.c 中的函数 compute_creds)。当前正在运行的进程保留它们启动时的功能。

修改现有进程的功能将我们引入下一节,这里就是我上面提到的陷阱。在不带参数的情况下运行 lcap 会列出您的系统能够支持的功能。如果您看到 CAP_SETPCAP 已禁用,则需要更改您的内核。在这里描述很简单。在内核源代码树中,编辑 include/linux/capability.h。您要更改以下行

#define CAP_INIT_EFF_SET
to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
#define CAP_INIT_INH_SET  to_cap_t(0)

使它们读取为

#define CAP_INIT_EFF_SET  to_cap_t(~0)
#define CAP_INIT_INH_SET  to_cap_t(~0)
然后重新编译。

实际上,CAP_SETPCAP 默认禁用是有原因的:在生产系统上启用它被认为是安全风险(针对这种情况的补丁已经存在,但在撰写本文时尚未应用)。为了安全起见,请务必在您玩完后删除此功能。

系统调用接口

在撰写本文时,系统调用 capset 和 capget 用于操作进程的功能。不能保证此接口不会更改。建议便携式应用程序使用 libcap (www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4) 代替。

capset 的原型是

int capset(cap_user_header_t header,
const cap_user_data_t data);

HEADER 是一种花哨的说法,表示您正在操作哪个 pid

typedef struct __user_cap_header_struct {
        __u32 version;
        int pid;
} *cap_user_header_t;
如果 pid 为 -1,您将修改所有当前正在运行的进程的功能。如果小于 -1,您将修改进程组,该进程组等于 pid 乘以 -1。语义类似于 kill(2) 的语义。

DATA 参数允许您选择计划修改的功能集。有三个

typedef struct __user_cap_data_struct {
        __u32 effective;
        __u32 permitted;
        __u32 inheritable;
} *cap_user_data_t;

permitted 集包含进程最终能够实现的所有功能。

effective 集是进程已选择从其 permitted 集中利用的功能。这就像您拥有庞大的诗歌库(permitted 集),但只选择用艾伦·金斯堡来武装自己以完成手头的任务(effective 集)。

inheritable 集定义了哪些功能可以传递给任何通过 exec(2) 替换当前进程映像的程序。请注意,fork(2) 对功能没有任何特殊处理。子进程只是接收所有三个功能集的精确副本。

只有 permitted 集中的功能才能添加到 effective 或 inheritable 集。除非设置了 CAP_SETPCAP,否则无法将功能添加到进程的 permitted 集。

文件系统接口

遗憾的是,功能仍然缺乏文件系统支持,这在一定程度上限制了它们的实用性。总有一天,主流内核将允许您在程序的 inode 中启用功能,从而在许多系统实用程序中消除 setuid 位。

一旦完全支持,允许 ping 实用程序打开原始套接字可以像

chattr +CAP_NET_RAW /bin/ping

不幸的是,更紧迫的内核问题延迟了这方面的工作。

如果您有兴趣,您可以使用 libcap 来 hack 您最喜欢的服务,以便它们能够识别功能并在启动时删除它们不再需要的权限。已经存在针对 xntpd 的几个补丁可以做到这一点;有些甚至提供其修改后的 RPM 版本。如果您对某个您经常抱怨的 root 级别进程的 capability-aware 版本感兴趣,请尝试 Google 搜索。

setpcap 可用于修改现有进程的功能集。例如,如果常规用户的 shell 的 PID 为 4235,以下是如何授予该用户的 shell 向任何进程发送信号的能力的方法

setpcaps 'cap_kill=ep' 4235

一个示例用途是允许使用您机器的朋友调试 CGI 脚本,以杀死任何卡在无限循环中的 Apache 进程。您只需针对他们的登录 shell 运行一次,然后就可以忘记它们了。

这是一个示例,它利用 execcap 和 sucap 以用户 “nobody” 身份运行 ping,仅具有 CAP_NET_RAW 功能。我们为 ping 选择的目标是 www.yahoo.com

execcap 'cap_net_raw=ep' /sbin/sucap nobody
nobody /bin/ping www.yahoo.com

这个示例不是很有用,因为您需要 root 权限才能执行它,但它确实说明了什么是可能的。尽管存在一些缺点,系统管理员仍然可以采取措施来提高其系统的安全性。一个没有 CAP_SYS_BOOT、CAP_SYS_RAWIO 和 CAP_SYS_MODULE 的系统对于入侵者来说极其难以修改。他们无法 hack 内核内存、安装新模块或重新启动系统,使其运行后门内核。

如果您的系统日志是仅追加的,并且您的核心系统实用程序是不可变的(有关详细信息,请参阅 chattr(3)),则删除 CAP_LINUX_IMMUTABLE 功能将使入侵者几乎不可能抹去他们的踪迹或安装被破坏的实用程序。一旦删除了 CAP_NET_RAW,像 tcpdump 这样的流量嗅探器将变得不可用。删除 CAP_SYS_PTRACE,您就关闭了程序调试。这种充满敌意的环境是脚本小子最糟糕的噩梦,他们别无选择,只能断开连接并等待入侵被发现。

结论

功能可以为 Linux 系统的所有方面提供复杂、细粒度的访问控制。最后,安全偏执狂将拥有他们如此迫切需要的工具,来对抗他们无休止的“他们”。

资源

Taking Advantage of Linux Capabilities
Michael Bacarella (mike@bacarella.com) 是 Netgraft Corporation 的总裁,该公司专门从事 Web 系统开发和信息安全分析。他与他美好的未婚妻和一只最可怕的绿色鬣蜥(鬣蜥的名字叫 Kang)在纽约合租一套公寓。
加载 Disqus 评论