无法让 CAP_CHOWN 和 CAP_DAC_OVERRIDE 为普通用户工作
Unable to get CAP_CHOWN and CAP_DAC_OVERRIDE working for regular user
我的要求
我的 python 服务器在 RHEL 上以普通用户身份运行
但是它需要在它无法访问的地方创建 files/directories 。
还需要随机 UID/GID
chown 那些文件
我的做法
在仅功能环境中尝试此操作,没有 setuid。
我正在尝试使用 cap_chown 和 cap_dac_override 功能。
但是我完全不知道如何让它在 systemctl 类型的环境中工作
目前我的服务文件中有以下内容:
#cat /usr/lib/systemd/system/my_server.service
[Service]
Type=simple
SecureBits=keep-caps
User=testuser
CapabilityBoundingSet=~
Capabilities=cap_dac_override,cap_chown=eip
ExecStart=/usr/bin/linux_capability_test.py
然后是二进制文件本身:
# getcap /usr/bin/linux_capability_test.py
/usr/bin/linux_capability_test.py = cap_chown,cap_dac_override+ei
但是这里说的是,它永远不会在脚本上运行:
Is there a way for non-root processes to bind to "privileged" ports on Linux?
在当前设置下,我对 运行 进程的能力是:
# ps -ef | grep lin
testuser 28268 1 0 22:31 ? 00:00:00 python /usr/bin/linux_capability_test.py
# getpcaps 28268
Capabilities for `28268': = cap_chown,cap_dac_override+i
但是如果我尝试从该脚本中在 /etc/ 中创建文件:
try:
file_name = '/etc/junk'
with open(file_name, 'w') as f:
os.utime(file_name,None)
失败 'Permission denied'
我也是一样的情况,不行吗?
我可以在这里使用 python-prctl 模块让它工作吗?
setuid 不适用于脚本,因为它是一个安全漏洞,由脚本执行的方式决定。有几个文件与此有关。您甚至可以从查看维基百科页面开始。
一个非常好的解决方法是编写一个小的 C 程序,它将启动您的 Python 脚本,其中包含 python 和脚本的硬编码路径。可以找到对所有问题的非常好的讨论 here
更新: 一种方法,不知道是不是最好的。使用 'python-prctl' 模块:
1. Ditch 'User=testuser' from my-server.service
2. Start server as root
3. Set 'keep_caps' flag True
4. Do 'setgroups, setgid and setuid'
5. And immediately limit the permitted capability set to 'DAC_OVERRIDE' and 'CHOWN' capability only
6. Set the effective capability for both to True
这是相同的代码
import prctl
prctl.securebits.keep_caps = True
os.setgroups([160])
os.setgid(160)
os.setuid(160)
prctl.cap_permitted.limit(prctl.CAP_CHOWN, prctl.CAP_DAC_OVERRIDE)
prctl.cap_effective.dac_override = True
prctl.cap_effective.chown = True`
完成!!
根据我们上面的讨论,我做了以下事情:
[Service]
Type=simple
User=testuser
SecureBits=keep-caps
Capabilities=cap_chown,cap_dac_override=i
ExecStart=/usr/bin/linux_capability_test.py
这将启动具有可继承功能的服务器。
写了一个小C,测试代码到chown文件
#include <unistd.h>
int main()
{
int ret = 0;
ret = chown("/etc/junk", 160, 160);
return ret;
}
在 gcc 的二进制文件上设置以下内容
chown testuser:testuser /usr/bin/chown_c
chmod 550 /usr/bin/chown_c
setcap cap_chown,cap_dac_override=ie /usr/bin/chown_c
服务器执行以下操作来调用二进制文件
import prctl
prctl.cap_inheritable.chown = True
prctl.cap_inheritable.dac_override = True
execve('/usr/bin/chown_c',[],os.environ)
我得到了想要的结果
# ll /etc/junk
-rw-r--r-- 1 root root 0 Aug 8 22:33 /etc/junk
# python capability_client.py
# ll /etc/junk
-rw-r--r-- 1 testuser testuser 0 Aug 8 22:33 /etc/junk
我的要求
我的 python 服务器在 RHEL 上以普通用户身份运行 但是它需要在它无法访问的地方创建 files/directories 。 还需要随机 UID/GID
chown 那些文件我的做法
在仅功能环境中尝试此操作,没有 setuid。 我正在尝试使用 cap_chown 和 cap_dac_override 功能。 但是我完全不知道如何让它在 systemctl 类型的环境中工作
目前我的服务文件中有以下内容:
#cat /usr/lib/systemd/system/my_server.service
[Service]
Type=simple
SecureBits=keep-caps
User=testuser
CapabilityBoundingSet=~
Capabilities=cap_dac_override,cap_chown=eip
ExecStart=/usr/bin/linux_capability_test.py
然后是二进制文件本身:
# getcap /usr/bin/linux_capability_test.py
/usr/bin/linux_capability_test.py = cap_chown,cap_dac_override+ei
但是这里说的是,它永远不会在脚本上运行: Is there a way for non-root processes to bind to "privileged" ports on Linux?
在当前设置下,我对 运行 进程的能力是:
# ps -ef | grep lin
testuser 28268 1 0 22:31 ? 00:00:00 python /usr/bin/linux_capability_test.py
# getpcaps 28268
Capabilities for `28268': = cap_chown,cap_dac_override+i
但是如果我尝试从该脚本中在 /etc/ 中创建文件:
try:
file_name = '/etc/junk'
with open(file_name, 'w') as f:
os.utime(file_name,None)
失败 'Permission denied'
我也是一样的情况,不行吗? 我可以在这里使用 python-prctl 模块让它工作吗?
setuid 不适用于脚本,因为它是一个安全漏洞,由脚本执行的方式决定。有几个文件与此有关。您甚至可以从查看维基百科页面开始。
一个非常好的解决方法是编写一个小的 C 程序,它将启动您的 Python 脚本,其中包含 python 和脚本的硬编码路径。可以找到对所有问题的非常好的讨论 here
更新: 一种方法,不知道是不是最好的。使用 'python-prctl' 模块:
1. Ditch 'User=testuser' from my-server.service
2. Start server as root
3. Set 'keep_caps' flag True
4. Do 'setgroups, setgid and setuid'
5. And immediately limit the permitted capability set to 'DAC_OVERRIDE' and 'CHOWN' capability only
6. Set the effective capability for both to True
这是相同的代码
import prctl
prctl.securebits.keep_caps = True
os.setgroups([160])
os.setgid(160)
os.setuid(160)
prctl.cap_permitted.limit(prctl.CAP_CHOWN, prctl.CAP_DAC_OVERRIDE)
prctl.cap_effective.dac_override = True
prctl.cap_effective.chown = True`
完成!!
根据我们上面的讨论,我做了以下事情:
[Service]
Type=simple
User=testuser
SecureBits=keep-caps
Capabilities=cap_chown,cap_dac_override=i
ExecStart=/usr/bin/linux_capability_test.py
这将启动具有可继承功能的服务器。
写了一个小C,测试代码到chown文件
#include <unistd.h>
int main()
{
int ret = 0;
ret = chown("/etc/junk", 160, 160);
return ret;
}
在 gcc 的二进制文件上设置以下内容
chown testuser:testuser /usr/bin/chown_c
chmod 550 /usr/bin/chown_c
setcap cap_chown,cap_dac_override=ie /usr/bin/chown_c
服务器执行以下操作来调用二进制文件
import prctl
prctl.cap_inheritable.chown = True
prctl.cap_inheritable.dac_override = True
execve('/usr/bin/chown_c',[],os.environ)
我得到了想要的结果
# ll /etc/junk
-rw-r--r-- 1 root root 0 Aug 8 22:33 /etc/junk
# python capability_client.py
# ll /etc/junk
-rw-r--r-- 1 testuser testuser 0 Aug 8 22:33 /etc/junk