10

在 Linux 系统上,可以比使用文件功能添加 setuid 位更有选择性地授予 root 权限。详情请参阅capabilities(7)。这些是文件的属性,可以使用getcap程序读取。如何在 Python 中检索这些属性?

即使getcap使用例如来运行程序来subprocess回答这样的问题是可能的,但在检索非常多的能力时它是不可取的。

应该可以使用ctypes. 是否有这种方法的替代品,甚至有图书馆促进这项任务?

4

2 回答 2

6

Python 3.3 带有os.getxattr. 如果不是,是的......一种方法是使用ctypes,至少是为了得到原始的东西,或者也许使用pyxattr

对于pyxattr

>>> import xattr
>>> xattr.listxattr("/bin/ping")
(u'security.capability',)
>>> xattr.getxattr("/bin/ping", "security.capability")
'\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

对于 Python 3.3 的版本,它本质上是一样的,只是导入os. 而不是xattr. ctypes不过,涉及更多。

现在,我们得到了原始结果,这意味着这两个最有用的只是检索文本属性。但是......我们可以getcap通过libcap自身使用相同的方法:

import ctypes

libcap = ctypes.cdll.LoadLibrary("libcap.so")
cap_t = libcap.cap_get_file('/bin/ping')
libcap.cap_to_text.restype = ctypes.c_char_p
libcap.cap_to_text(cap_t, None)

这给了我:

'= cap_net_raw+p'

可能对你更有用。

PS:注意cap_to_text返回一个malloced 字符串。你的工作是使用它来释放它cap_free

关于“二进制乱码”的提示:

>>> import struct
>>> caps = '\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> struct.unpack("<IIIII", caps)
(33554432, 8192, 0, 0, 0)

其中8192,唯一有效的位是第 13 位。如果你去linux/capability.h,你会看到CAP_NET_RAW定义在13

现在,如果你想用所有这些常量编写一个模块,你可以解码信息。但我想说这比使用ctypes+更费力libcap

于 2014-02-04T19:31:30.220 回答
0

我尝试了 Ricardo Cárdenes 回答中的代码,但它对我来说不能正常工作,因为ctypes调用的一些细节不正确。此问题导致将截断的路径字符串传递到getxattr(...)内部libcap,从而为错误的项目(/目录或其他第一个路径字符,而不是实际路径)返回错误的功能列表。

str记住和解释bytesPython 3.X之间的区别非常重要。此代码在 Python 3.5/3.6 上正常工作:

#!/usr/bin/env python3

import ctypes
import os
import sys

# load shared library
libcap = ctypes.cdll.LoadLibrary('libcap.so')

class libcap_auto_c_char_p(ctypes.c_char_p):
    def __del__(self):
        libcap.cap_free(self)

# cap_t cap_get_file(const char *path_p)
libcap.cap_get_file.argtypes = [ctypes.c_char_p]
libcap.cap_get_file.restype  = ctypes.c_void_p

# char* cap_to_text(cap_t caps, ssize_t *length_p)
libcap.cap_to_text.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
libcap.cap_to_text.restype  = libcap_auto_c_char_p

def cap_get_file(path):
    cap_t = libcap.cap_get_file(path.encode('utf-8'))
    if cap_t is None:
        return ''
    else:
        return libcap.cap_to_text(cap_t, None).value.decode('utf-8')

print(cap_get_file('/usr/bin/traceroute6.iputils'))
print(cap_get_file('/usr/bin/systemd-detect-virt'))
print(cap_get_file('/usr/bin/mtr'))
print(cap_get_file('/usr/bin/tar'))
print(cap_get_file('/usr/bin/bogus'))

输出将如下所示(任何不存在或没有设置功能的内容都将返回''

= cap_net_raw+ep
= cap_dac_override,cap_sys_ptrace+ep
= cap_net_raw+ep
于 2018-04-25T18:45:55.237 回答