Linux 能力(Capabilities)机制再探
致内核开发者的说明:能力(Capabilities)机制旨在将超级用户的权限拆分为若干部分,使得当某个拥有单一或多项能力的程序遭到入侵时,其对系统造成的破坏程度将小于该程序以root权限运行时的破坏力。 Capabilities(7) — Linux手册页
能力机制(Capabilities)是 Linux 中一种精细化的访问控制机制,相较于传统的超级用户(root)模型,它能实现更细粒度的权限控制。该机制将通常与 root 用户关联的特权拆分为独立单元,可针对不同进程单独启用或禁用。这使得特权管理更安全且可控。
例如,某个进程可能仅需绑定特权端口的权限,而无需其他提升权限。
能力(Capabilities)机制解析
要查看 Linux 主机支持的能力数量,可查询 /proc 目录下的 cap_last_cap 文件:
# cat /proc/sys/kernel/cap_last_cap
40
capsh --print 命令会显示当前 shell 或调用该命令的进程所拥有的能力及相关设置。在 Linux 主机上执行此命令时,可查看完整的能力列表。
# capsh --print
Current: =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,cap_perfmon,cap_bpf,cap_checkpoint_restore
每项能力对应特定的特权操作。
Python后门技术
setcap命令用于设置可执行文件的能力。cap_setuid能力允许进程任意操作用户ID(UID),包括设置受限值(如UID 0即root用户)。setcap 接受以下参数:
e:有效(表示能力被激活)p:允许(表示能力可被使用/被许可)
综合上述,我们为 Python 二进制文件添加 cap_setuid 能力:
# setcap cap_setuid+ep /usr/bin/python3.12
支持的能力列表可在此处查阅:
# cat /usr/include/linux/capability.h
测试
为验证效果,我们创建新用户(malmoeb)并切换至该用户环境(useradd && su):
# useradd -m malmoeb
# su malmoeb
$ id
uid=1000(malmoeb) gid=1000(malmoeb) groups=1000(malmoeb)
通过以下命令行,我们将Python调用的bash shell用户ID设为0(UID 0 == root),从而成功生成root权限shell:
$ /usr/bin/python3 -c 'import os;os.setuid(0);os.system("/bin/bash")'
# id
uid=0(root) gid=1000(malmoeb) groups=1000(malmoeb)
该技术令人振奋之处在于:我们既未设置二进制文件的suid位,也未修改Python二进制文件。仅通过设置能力,攻击者便能构建强大的后门。
漏洞追踪
传统上,系统管理员和安全专家主要关注SUID(设置用户ID)和SGID(设置组ID)文件,因这些文件在特定条件下可用于提升权限。然而随着POSIX权限机制的引入,如上所述,追踪具有权限设置的文件同样重要。
通过命令getcap -r可枚举所有启用能力的二进制文件:
# getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin,cap_sys_nice=ep
/usr/bin/mtr-packet cap_net_raw=ep
/usr/bin/ping cap_net_raw=ep
/usr/bin/python3.12 cap_setuid=ep
在/proc目录中:
# cat /proc/1143966/status | grep Cap
其中:
CapInh= 继承能力CapPrm= 允许能力CapEff= 有效能力CapBnd= 边界集CapAmb= 环境能力集
使用命令 capsh 可解码能力信息:
# capsh --decode=0000000000000080
0x0000000000000080=cap_setuid
或通过命令 getpcaps 并传入进程ID作为参数:
# getpcaps 1143966
Capabilities for `1143966': = cap_setuid+ep
使用 setcap -r 从二进制文件移除能力
# setcap -r /usr/bin/python3.12
LinPeas
LinPEAS——即 Linux权限提升超级脚本——同样会执行检测以发现(有价值的)能力。以下命令直接摘自相关 脚本中的命令:
- 当前shell能力:
cat “/proc/$$/status” - 父进程能力:
cat “/proc/$PPID/status” - 含能力文件:
getcap -r / 2>/dev/null
除检测suid文件外,LinPEAS在此处对搜索前述(隐藏)能力表现尤为出色。
Elastic规则:通过setcap工具设置进程能力集
Elastic规则“检测使用setcap工具为进程设置能力的情况”。完整描述详见此处。
process where host.os.type == "linux" and event.type == "start" and event.action in ("exec", "exec_event", "start") and
process.name == "setcap" and not (
process.parent.executable == null or
process.parent.executable : ("/var/lib/dpkg/*", "/var/lib/docker/*", "/tmp/newroot/*", "/var/tmp/newroot/*") or
process.parent.name in ("jem", "vzctl")
)
security.capability
扩展权限(如通过setfacl设置的访问控制列表(ACL)及通过setcap设置的能力标志)与传统权限位及通过chmod配置的setuid/setgid标志存储于同一位置:文件的inode。
ls命令不会显示由setcap设置的能力标志。要查看这些标志,请使用getcap。若需列出所有扩展属性,可使用getfattr -d -m -。setcap使用的属性是security.capability,其存储为二进制格式,而getcap能为您便捷地解码该格式。
# getfattr -d -m - /usr/bin/python3.12
getfattr: Removing leading '/' from absolute path names
# file: usr/bin/python3.12
security.capability=0sAQAAAoAAAAAAAAAAAAAAAAAAAAA=
结论
尽管传统 SUID/SGID 检查依然重要,现代安全实践必须包含对特定能力设置文件的追踪。能力机制提供更精细且可能隐蔽的权限授予方式,若缺乏监控将引发重大安全风险。使用 getcap 等工具递归扫描文件系统中的能力设置,是确保全面安全审计并消除潜在攻击向量的关键措施。
本文未涉及存储于etc/security/capability.conf配置文件的用户能力,以及可指定AmbientCapabilities的服务文件。后续章节将推荐两份深入探讨该主题的优质资源。
参考资料
若需深入研究此主题,推荐访问以下两个网站:
本文文字及图片出自 Linux Capabilities Revisited

我认为Linux对能力机制的处理令人失望,甚至远未达到真正的基于能力的安全系统标准。
例如,你可以向程序传递绑定 任意 特权端口的能力,却无法指定具体端口。对于这种场景,直接传递绑定该端口的文件描述符(fd)实际上更简单安全。至于其他能力机制,它们的粒度也过于粗糙。
能力默认隐式继承的设计在安全性上也存在缺陷。虽然这可能是出于向后兼容的考虑,但我认为能力应当显式传递,且支持进程间转移。实际上,将文件描述符作为能力句柄使用,或许才是更清晰明确的方案。
文件描述符访问文件正是Linux遵循能力模型的典型场景。值得注意的是,该机制作为Linux API的一部分,至今未被证实存在显著攻击漏洞。
这误解了该功能的初衷。该功能的初衷并非从零构建“基于权限的系统”(相关工作可参考LSM/selinux/apparmor),而是将“setuid传统应用场景”拆解为更精细的权限单元。
setuid二进制文件本就存在,此方案旨在不修改API的前提下大幅提升其安全性。
若这些能力不以FILE*/fd这类对象形式传递,它们甚至算不上真正的能力,仅是(闪闪发光的)精细化环境权限(需明确的是,这种权限仍有价值)。
共享的全局命名空间最终会严重阻碍构建完善的基于能力的系统。要建立合理的运作机制,必须采用基于操作集的命名空间,并建立能力继承层次——子进程只能继承父进程拥有的能力。正如封装使程序抽象更易理解,这种嵌套能力层次也便于分析系统各部分的特权。而当前混乱的局面中,无人能清晰厘清权限归属关系。
需注意这仅是细分 root 权限的一组标志位,虽较之前有所改进,但远非真正的基于能力的安全机制
https://en.wikipedia.org/wiki/Capability-based_security
(如AS/400或iAPX 432系统中,“能力”代表关联特权的系统对象引用)。这种机制完全可移植到POSIX类系统中
https://en.wikipedia.org/wiki/Capsicum_(Unix)
这让我想起高中时使用搭载VMS操作系统的VAX-11/730主机,当时进程可拥有的权限列表冗长
https://hunter.goatley.com/vax-professional-articles/vax-pro…
当时流行玩这样的游戏:探索“若同时拥有A、B、C特权,就能获取SETPRV权限并接管整台机器”的途径
真正能力机制的最大优势在于规避“困惑代理人问题”。这类系统通过将操作行为与执行理由永久绑定来实现: 因此,代表A和B行事的代理人,不会误用B的权限执行A的操作。
但Linux的“能力机制”并未解决此问题。只要拥有权限,就能执行操作——即便操作动机(满足A请求所需)与权限来源动机(执行B任务所需)存在矛盾。
macOS与iOS基于mach内核的安全研究中存在高度相似的流程。研究者会寻找易于权限提升的开放mach端口。
通过SeL4和CHERI技术可实现大部分目标。
Linux能力机制与传统基于对象能力的安保概念关联甚微。
其更接近苹果权限体系,但通过进程分叉继承而非绑定至二进制文件。
即便粒度不够精细,OpenBSD的权限体系设计仍堪称典范。
其次我支持FreeBSD的capsicum方案。
OpenBSD的权限机制简洁易用,真希望Linux能采纳。Seccomp的实现简直是噩梦。
与其采用seccomp、selinux和apparmor这类复杂到近乎发烧的方案,我宁愿选择简单粗放的机制。那些几乎达到图灵完备的语言实现简直是自掘深坑的陷阱,只会让你陷入万丈深渊。
我敢说,99% 的用例中,Pledge 的简单性就足够用了,而且它很容易集成到现有代码中。
有一个移植版本…
这个底层使用seccomp且需要定制libc吧?
确实是个好项目,但我不确定是否会在生产环境中使用。
我不同意。Pledge要求每个应用主动选择加入安全机制。这意味着多数应用不会采用,而采用的应用很可能偷懒,仅限制其原有功能使用范围,不会重新设计架构。
难道因为工具不会被百分之百地正确使用,我们就该放弃提供基础强化工具?安全圈这种思维模式必须改变。
若重要基础软件想实现自我加固,看看其他评论里那些繁琐复杂的“解决方案”就知道了。若想阻碍该领域进步,这正是设计方案应有的模样。我并非指责恶意,但这种思维无疑源于无休止的吹毛求疵和“不够好,没覆盖<小众场景>”的偏执。
编辑:
> 而那些付诸行动的开发者很可能只是偷懒
我持相反观点:任何愿意花时间在代码中添加安全调用的开发者,多半是重视安全并希望改进的人。若真想偷懒,大可干脆不实现安全机制——毕竟它会妨碍开发且限制太多。
问题不在于不该提供该功能,而在于当OpenBSD的安全性远落后于行业标准时,投入资源开发毫无意义。程序能在用户毫不知情的情况下窃取.ssh密钥是不可接受的。不仅如此,程序还能记录键盘操作、拍摄屏幕画面,甚至远程控制你的计算机。
我怀疑你根本无法监控我通过SSH或串口远程连接的OpenBSD服务器。
更别说在没有摄像头的情况下拍摄我的画面——即便装了摄像头,你看到的也只会是闪烁的LED灯和一堆线缆。
即使我将OpenSSH对公众开放,我也极度怀疑你能实现远程控制。
或许你们行业根本不在乎OpenBSD社区关注的安全问题。
编辑:遗漏了SSH密钥窃取风险。我的密钥始终处于加密状态。
Bash别名和PATH环境变量缺乏保护,恶意软件可将ssh替换为其他命令,进而窃取加密密码解密密钥。
SELinux等工具允许管理员在程序运行前设置限制,如同护栏般防护。
pledge()则让开发者能在运行时动态加固程序,更像是防御性驾驶。
两者都是实用的技术手段。
虽然使用场景有限,但某些应用确实需要。例如允许封装任意应用的工具https://wiki.alpinelinux.org/wiki/Bubblewrap
关键在于它更有效。像pledge/unveil这样的简易API能让应用在无需大量投入的情况下显著提升安全等级。
而像SELinux这类复杂的外部系统最终往往被闲置,因为它们既复杂又独立(因此可以被直接忽略)。
> 而像SELinux这类复杂的外部系统最终往往被闲置,因为它们既复杂又独立(因此可以被直接忽略)。
你什么意思?它在Android系统中应用非常广泛啊
没错,因为他们有工程师团队专门维护。他们负担得起。
我从未见过常规服务器使用SELinux。天啊,AWS上的Amazon Linux AMI默认甚至禁用了它。
是是是,个人经验之谈罢了。
>它效果更好
并非如此。恶意软件仍可下载,应用甚至能加密锁定整个系统。当然,如果恶意软件像Pledge那样阻止文件打开——但哪有恶意软件会这么做?
我认为无法像你描述那样将新机制硬塞进现有内核(就像Linux添加能力机制那样)。必须从底层重新设计。我记得读过某些实验性操作系统在探索这种设计能力,类似于进程层面的第一类虚拟机监控程序。
Fuchsia系统广泛采用能力机制。
> 其中子进程只能获得父进程拥有的能力
能力机制的实用性恰恰在于它不必遵循这条规则。
若程序无法从创建者之外的来源获取能力,不如直接将程序名加入访问控制列表(ACL)更有效。
需注意命名空间本质上就是能力机制。
我对精细化访问控制列表(ACL)的一个顾虑在于,它们可能无意中增加安全风险——因为有时这些更精细的控制措施会被利用来获取额外权限。
如果我授予某个对象root权限,我清楚这意味着什么且会格外谨慎。但如果我以为授予权限X很安全,结果它却能被用来获取权限Y甚至root权限,那么我就可能意外暴露风险。
细粒度权限需要防范的攻击面更大,必须确保每个细粒度权限都不会被如此利用。
无论采用细粒度还是粗粒度权限,这都是个挑战。
粗粒度权限需要依赖代理机制——这虽能自由实现业务逻辑,却也带来巨大负担:既要编写代理代码,又要维护客户端调用协议,后续还需持续维护扩展。
无论哪种方式都需进行审计和静态分析以查找权限提升途径,而精细化权限下的分析难度更大——但并非不可克服。
因此我认为精细化权限更胜一筹。
我已实现(并正争取发表论文许可)一种融合RBAC式与SMACK式标记安全(采用人类可读的字符串标记而非MLS式的位图+等级)的应用层授权方案,其运行速度极快,若有人需要也可在内核中实现。该系统通过使用大量独立标签(精细粒度)或少量标签(粗放粒度)标记应用程序(或内核)对象,实现任意粒度的授权控制。
实现该功能需Linux具备集中化权限管理机制。通过审查(或比较)文件即可立即掌握变更内容,无需遍历各处访问控制列表。
采用传统Unix /etc/group样式。
Linux能力机制在Linux安全模块(LSM)系统中设有钩子,因此可编写LSM模块实现任意集中化管理系统。
我熟悉的LSM仅限SELinux,其能力直接作为SELinux权限存在。推测多数通用LSM实现原理相近。
我设想过基于UID/GID分配能力的LSM策略,但目前尚未发现实际应用此机制的LSM实现。
非常有趣,感谢分享。