编辑-1

编辑-1

我正在 Debian Gnu/Linux 上试验各种功能。

我已将 /bin/ping 复制到当前工作目录。果然不行,原来是setuid root。

然后,我通过执行 ping 操作来赋予我的 ping 最小功能(不是 root)sudo /sbin/setcap cap_net_raw=ep ./ping,并且我的 ping 可以按预期工作。

然后sudo /sbin/setcap -r ./ping撤销该能力。现在它没有按预期工作。

我现在尝试使用 ping 来工作capsh

capsh没有权限,所以我需要以 root 身份运行它,然后删除 root 权限,从而删除所有其他权限。

我想我还需要secure-keep-caps,这没有记录在 中capsh,但在功能手册中。我从 得到了位数/usr/include/linux/securebits.h。它们看起来是正确的,因为 的输出--print显示这些位是正确的。

我已经摆弄了几个小时,到目前为止我已经有了这个。

sudo /sbin/capsh --keep=1 --secbits=0x10 --caps="cap_net_raw+epi" == --secbits=0x10 --user=${USER} --print -- -c "./ping localhost"

然而pingping: icmp open socket: Operation not permitted当它不具备该功能时会发生这种情况。同时也--print表明Current: =p cap_net_raw+i,这还不够我们所需要的e

sudo /sbin/capsh --caps="cap_net_raw+epi" --print -- -c "./ping localhost"将能力设置为此Current: = cap_net_raw+eip是正确的,但将我们保留为root.

编辑-1

我现在已经尝试过sudo /sbin/capsh --keep=1 --secbits=0x11 --caps=cap_net_raw+epi --print -- -c "touch zz; ./ping -c1 localhost;"

这会产生:

touch: cannot touch `zz': Permission denied
ping: icmp open socket: Operation not permitted

第一个错误预计为secure-noroot: yes 但第二个错误不是Current: = cap_net_raw+eip

编辑2

如果我放在==之前--print,它现在显示Current: = cap_net_raw+i,这样就解释了之前的错误,但不是为什么我们在切换出 root 时会失去能力,我认为这secure-keep-caps应该可以解决这个问题。

编辑3

据我所见,当调用 exec 时,我失去了有效(e)和允许(p)。这是预料之中的,但我认为安全保存帽应该可以防止它们丢失。我是不是错过了什么。

编辑4

我做了更多研究,并再次阅读了手册。当您从用户切换(或 apply ,从而使 root 成为普通用户)时,通常e和功能似乎会丢失,这可以用;覆盖当你打电话时,据我所知这是一个不变量。prootsecure-norootsecure-keep-capsexec

据我所知,它正在按照手册工作。据我所知,没有办法做任何有用的事情capsh。据我所知,要使用功能,您需要:使用文件功能或拥有功能感知程序,该程序不使用exec.因此没有特权包装器。

所以现在我的问题是我错过了什么,我capsh的目的是什么。

编辑5

我添加了有关环境功能的答案。也许capsh也可以与继承的功能一起使用,但为了有用,需要在可执行文件上设置这些功能。我不明白 capsh 如何在没有环境功能或允许继承功能的情况下做任何有用的事情。


版本:

  • capsh从包libcap2-bin版本1:2.22-1.2
  • 在 edit-3 之前,我获取了最新版本capshgit://git.debian.org/collab-maint/libcap2.git开始使用它。
  • uname -a Linux richard-laptop 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u2 x86_64 GNU/Linux 用户空间是32位的。

答案1

能力是流程的属性。传统上有三组:

  • 允许的能力(p):可以在当前进程中“激活”的功能。
  • 有效能力(e):当前进程中当前可用的能力。
  • 可遗传的能力():可以继承的文件能力。

以 root 身份运行的程序始终具有完全允许且有效的功能,因此“添加”更多功能不会产生明显的效果。 (可继承的功能集通常为空。)setcap cap_net_raw+ep ping默认情况下,您将为运行此程序的任何用户启用这些功能。

不幸的是,这些功能绑定到执行的文件,并且在执行新的子进程后不会保留。 Linux 4.3 推出环境能力它允许子进程继承功能。 (也可以看看execve() 期间功能的转换能力(7).)

在使用功能时,请注意以下陷阱:

  • 当将用户从 root 更改为非 root 时,有效和允许的权限将被清除(请参见用户 ID 更改对功能的影响能力(7))。您可以使用--keep=1选项来capsh避免清除集合。
  • 更改用户或组 ID 时,环境功能集将被清除。解决方案:添加环境功能更改用户ID,但是执行子进程。
  • 仅当某个功能已同时位于允许的功能集和可继承的功能集中时,才能将其添加到环境功能集中。

从 libcap 2.26 开始,capsh程序获得了通过以下选项修改环境功能的能力--addamb犯罪)。请注意,选项顺序很重要。用法示例:

sudo capsh --caps="cap_net_raw+eip cap_setpcap,cap_setuid,cap_setgid+ep" \
    --keep=1 --user=nobody --addamb=cap_net_raw -- \
    -c "./ping -c1 127.0.0.1"

提示:您可以--print在命令行中的任意位置添加该选项capsh并查看其当前的功能状态。

注意:cap_setpcap是必需的,--addamb而选项cap_setuid,cap_setgid则需要--user

答案2

Lekensteyn 的答案似乎准确且完整,但我将尝试从不同的角度提供另一种解释,试图强调环境功能集解决的问题。

当您运行时,sudo capsh --user=<some_user> --有 2 个系统调用会导致重新计算(并可能删除)功能:

  1. setuid: 根据man capabilities

SECBIT_KEEP_CAPS 设置此标志允许具有一个或多个 0 UID 的线程在将其所有 UID 切换为非零值时保留其功能。如果未设置此标志,则此类 UIDswitch 会导致线程失去所有功能。

换句话说,在capsh上面的命令中,我们需要确保在setuid系统调用期间设置了 SECBIT_KEEP_CAPS。否则所有能力都会丧失。这就是它--keep=1所做的。所以现在命令变成sudo capsh --user=<some_user> --keep=1 --

  1. execve:如果我们使用该--keep=1选项,则保留所有功能集(有效、允许、可继承)直到......为止但是,该execve系统调用execve也会导致重新计算权限(对于非 root 用户),而且方式不太明显。简而言之,在添加环境功能集之前,对于调用后线程“允许”集中的功能execve,可以:

    • 该文件必须在其“允许”集中具有该功能。这可以通过 来完成setcap cap_net_raw+p /bin/bash。这样做会使整个练习变得毫无用处,因为线程的功能集(除了边界集之外)不再有任何效果。
    • 文件和线程都必须在其“可继承”集中具有该功能。您可能认为这setcap cap_net_raw+i可以解决问题,但事实证明,execve当非特权用户调用时,这会导致线程的固有权限被删除(我们目前要感谢这一点setuid)。所以作为非特权用户没有办法满足这个条件。

Linux 4.3 中引入的环境功能使得线程即使在 asetuid给非特权用户后跟一个, 也能保留其功能execve无需依赖文件功能。

答案3

对 Lekensteyn 的答案进行轻微调整,可以缩短最近内核的调用时间:

sudo /usr/sbin/capsh --keep=1 --user=$USER \
  --inh=cap_net_raw --addamb=cap_net_raw -- \
  -c './ping -c1 localhost'

注意:根据您的 sudoers 文件,这可能会使您的环境变得混乱(例如更改 HOME)。 capsh 会更改您的 uid,但不会执行任何操作来恢复 sudo 的环境更改。

那么这是怎么回事呢?我们来看一下:

  • sudo /usr/sbin/capsh:我们从 root 开始,它在其有效(可以执行此操作)和允许(可以将其添加到有效)集中具有所有功能,但在其他集中没有任何功能。我们稍后将讨论其他集合。
  • --keep=1:出于安全(读取:遗留)原因,功能通常不会跨根->非根 ID 交换机继承。该标志启用了一项称为 的功能SECBIT_KEEP_CAPS,可以实现此目的。值得注意的是,它会在 exec 时自动清除,这是一个好主意。
  • --user=$USER:既然我们不会失去 UID 更改的所有功能,我们就退出 root 状态。感谢SECBIT_KEEP_CAPS,我们保留了类似 root 的权限,这让我们进一步混乱了我们的能力。
  • --inh=cap_net_raw:这会将我们的目标功能添加到可继承集中,因为如果功能不可继承,则无法将其设置为环境功能(请参阅下一项)。
  • --addamb=cap_net_raw:即使我们已经请求SECBIT_KEEP_CAPSexecve非特权(无 setuid/setgid/setcap)二进制文件也会仍然明确我们的能力,导致没有特权。 Linux 4.3 添加了环境集,在执行非特权二进制文件时,该环境集会添加回有效集和允许集。完美的!
  • -- -c ...:设置完所有内容后,我们使用这些参数执行 bash。功能集被清除(因为 bash 没有特权),环境集被添加回来,瞧!我们拥有打开原始套接字所需的权限。

您可以使用 capsh 的特殊==参数来检查这一点,这会导致它使用命令行的其余部分执行自身:

sudo /usr/sbin/capsh --keep=1 --user=$USER \
  --inh=cap_net_raw --addamb=cap_net_raw == --print

Current: = cap_net_raw+eip

这意味着我们将 cap_net_raw 视为有效(可以执行)、可继承(可以将其传递给子进程)和允许(允许获取)。其中没有任何其他功能。

有关功能及其工作方式的更多信息,您最好的选择是功能(7) 手册页。具体是标题Transformation of capabilities during execve()

答案4

setpriv命令比 .com 更容易处理行为capsh。考虑使用它来代替您问题的运行时功能部分。对零件没有太大影响setcap

$ setpriv --help

Usage:
 setpriv [options] <program> [<argument>...]

Run a program with different privilege settings.

现在,ping作为 Fedora 32 上的非特权用户,我可以正常工作:

$ cp /usr/bin/ping .
$ ./ping -c 1 ::1
PING ::1(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.030 ms

所以我选择了tcptraceroute

$ tcptraceroute ::1
Running:
    traceroute -T -O info ::1 
You do not have enough privileges to use this traceroute method.
socket: Operation not permitted

$ sudo setpriv --no-new-privs  --inh-caps '-all,+net_raw' --bounding-set '-all,+net_raw' tcptraceroute ::1
Running:
    traceroute -T -O info ::1 
traceroute to ::1 (::1), 30 hops max, 80 byte packets
 1  localhost (::1) <rst,ack>  0.041 ms  0.010 ms  0.007 ms

请注意,该命令没有广泛提升的权限:

$ sudo setpriv --no-new-privs  --inh-caps '-all,+net_raw' --bounding-set '-all,+net_raw' touch /root/secret
touch: cannot touch '/root/secret': Permission denied

$ sudo setpriv --no-new-privs  --inh-caps '-all,+net_raw' --bounding-set '-all,+net_raw' sudo touch /root/secret
sudo: PERM_SUDOERS: setresuid(-1, 1, -1): Operation not permitted
sudo: no valid sudoers sources found, quitting
sudo: error initializing audit plugin sudoers_audit

$ sudo setpriv --no-new-privs  --inh-caps '-all,+net_raw' --bounding-set '-all,+net_raw' id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

相关内容