setcap capabilities cap_net_raw

https://www.cnblogs.com/passzhang/p/12918766.html

CAP_SYS_RAWIO allows full access to the host systems memory with /proc/kcore, /dev/mem, and /dev/kmem 27, but a contained process would need mknod to access these within the namespace.28. 
But it also allows things like iopl and ioperm, which give raw access to the IO ports29.
ubuntu@ubuntu:~$ cp /bin/ping anotherping
ubuntu@ubuntu:~$ ./anotherping 
Usage: ping [-aAbBdDfhLnOqrRUvV64] [-c count] [-i interval] [-I interface]
            [-m mark] [-M pmtudisc_option] [-l preload] [-p pattern] [-Q tos]
            [-s packetsize] [-S sndbuf] [-t ttl] [-T timestamp_option]
            [-w deadline] [-W timeout] [hop1 ...] destination
Usage: ping -6 [-aAbBdDfhLnOqrRUvV] [-c count] [-i interval] [-I interface]
             [-l preload] [-m mark] [-M pmtudisc_option]
             [-N nodeinfo_option] [-p pattern] [-Q tclass] [-s packetsize]
             [-S sndbuf] [-t ttl] [-T timestamp_option] [-w deadline]
             [-W timeout] destination
ubuntu@ubuntu:~$ ./anotherping 8.8.8.8
ping: socket: Operation not permitted
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ ls -ls anotherping 
64 -rwxr-xr-x 1 ubuntu ubuntu 64184 Nov 17 19:26 anotherping
ubuntu@ubuntu:~$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=108 time=11.5 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 11.549/11.549/11.549/0.000 ms
ubuntu@ubuntu:~$ sudo setcap cap_net_raw+ep ./anotherping 
[sudo] password for ubuntu: 
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ ./anotherping -c1 www.163.com
PING z163ipv6.v.gddx.cdnyzdjj.com (183.47.233.7) 56(84) bytes of data.
64 bytes from 183.47.233.7 (183.47.233.7): icmp_seq=1 ttl=51 time=4.45 ms

--- z163ipv6.v.gddx.cdnyzdjj.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.456/4.456/4.456/0.000 ms
ubuntu@ubuntu:~$ 
root@ubuntu:/home/ubuntu# groupadd newGrp1
root@ubuntu:/home/ubuntu# groupadd newGrp2
root@ubuntu:/home/ubuntu# useradd -u 10000 -g root -G newGrp1,newGrp2 userTest1
root@ubuntu:/home/ubuntu# su userTest1
$ id
uid=10000(userTest1) gid=0(root) groups=0(root),1001(newGrp1),1002(newGrp2)
$ exit
root@ubuntu:/home/ubuntu# 
 root@ubuntu:/home/ubuntu# cat /etc/passwd | grep userTest1
userTest1:x:10000:0::/home/userTest1:/bin/sh
root@ubuntu:/home/ubuntu# 

此时进程执行主要涉及6个id:Real uid/gid,Effective uid/gid/supplementary group,Saved set-user-ID/saved set-group-ID。

下面分别用RUID, EUID,SUID来表示实际用户ID,有效用户ID,设置用户ID。另外用户ID是个整型数,为了说明方便真接使用了用户名来代表不同的UID。先解释一下这几个ID的作用:

RUID, 用于在系统中标识一个用户是谁,当用户使用用户名和密码成功登录后一个UNIX系统后就唯一确定了他的RUID.

EUID, 用于系统决定用户对系统资源的访问权限,通常情况下等于RUID。

SUID,用于对外权限的开放。跟RUID及EUID是用一个用户绑定不同,它是跟文件而不是跟用户绑定。

下面以不同的user id为例进行讲解,group id也是类似的。

  • supplementary group为user的增补组,例如在添加一个名为usetTest1的user时候,-g执行该user的primary group,-G指定该usetTest1的supplementary groups。使用id命令可以看到“gid=”后面对应usetTest1的primary group,“groups=”后面对应usetTest1的supplementary groups。supplementary groups可以用与DAC验证
[root@localhost ~]# groupadd newGrp1 [root@localhost ~]# groupadd newGrp2 [root@localhost ~]# useradd -u 10000 -g root -G newGrp1,newGrp2 userTest1 [root@localhost ~]# su userTest1 [userTest@localhost root]$ id uid=10000(userTest) gid=0(root) groups=0(root),1001(newGrp1),1002(newGrp2) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  • 进程的RUID为执行该进程的用户ID,该值通常不需要变更;当判断一个进程是否对某个可执行文件有权限时,需要验证EUID,在没有开启SUID功能时,EUID的值等于RUID;SUID主要用于设置EUID。

在上一步中创建了一个usetTest1用户,可以在/etc/passwd查看该用户的home目录,为/home/userTest1

userTest1:x:10000:0::/home/userTest1:/bin/bash

为验证SUID的功能,su切换到userTest1,并在/home/userTest1下创建一个空文件,可以看到wr.log仅对用户userTest1开放写权限

[userTest1@localhost ~]# touch wr.log[userTest1@localhost ~]# ll-rw-r--r--. 1 userTest1 root 10 Dec 13 18:50 wr.log

在/home/userTest1下编译一个小程序,用于查看当前进程的RUID,EUID和SUID,并写入wr.log。可以看到getIds对所有用户开发了可执行权限

#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { uid_t ruid; uid_t euid; uid_t suid; getresuid(&ruid, &euid, &suid); printf("real_user_id=%d, effictive_user_id=%d, saved_user_id=%d ",ruid,euid,suid); uid_t rgid; uid_t egid; uid_t sgid; getresgid(&rgid, &egid, &sgid); printf("real_group_id=%d, effictive_group_id=%d, saved_group_id=%d ",rgid,egid,sgid); FILE *stream; stream = fopen( "wr.log", "a+" ); fprintf( stream, "%s", "hello" ); fclose( stream ); return 0; }
total 20 -rwxr-xr-x. 1 userTest1 root 8712 Dec 13 18:50 getIds -rw-r--r--. 1 userTest1 root 554 Dec 13 18:50 getIds.c -rw-r--r--. 1 userTest1 root 10 Dec 13 18:50 wr.log

在userTest1用户下执行getIds,有如下内容,可以看到其UID为10000,跟创建该用户时设置的值是一样的,RUID=EUID;拉起该进程用户所在的group以及该文件所属的group都是root,所以group的数值显示均为0

[userTest1@localhost ~]$ ./getIds real_user_id=10000, effictive_user_id=10000, saved_user_id=10000 real_group_id=0, effictive_group_id=0, saved_group_id=0

在同一个host上创建不同组的用户userTest2。

[root@localhost ~]# groupadd -g 20001 newGrp3 [root@localhost home]# useradd -u 10001 -g newGrp3 userTest2

切换到用户userTest2,并进入/home/userTest1(可能需要为该目录添加other的rx权限)下执行getIds,但因为wr.log的用户和组是userTest1:root,而当前用户是userTest2:newGrp3,因此会因为无法打开wr.log出现段错误。同时也可以看到当前进程的RUDI=EUID=10001,即创建userTest2时的UID;RGID=EGID=20001,为创建newGrp3时的GID

[userTest2@localhost userTest1]$ ./getIds real_user_id=10001, effictive_user_id=10001, saved_user_id=10001 real_group_id=20001, effictive_group_id=20001, saved_group_id=20001 Segmentation fault (core dumped)

SUID的作用就是使可执行文件在不同用户下能以文件拥有者的权限去执行。在userTest1用户下为getIds添加SUID,此时getIds文件的权限中user对应的x变为了s

[userTest1@localhost ~]$ chmod 4755 getIds [userTest1@localhost ~]$ ll -rwsr-xr-x. 1 userTest1 root 8712 Dec 13 18:50 getIds -rw-r--r--. 1 userTest1 root 554 Dec 13 18:50 getIds.c -rw-r--r--. 1 userTest1 root 15 Dec 13 19:02 wr.log

切换到userTest2,执行getIds,此时可以执行成功,RUID没有变,但EUID和SUID变为了userTest1的值,此时EUID被SUID值为了10000。即当前程序使用userTest1的权限(EUID)去写入wr.log,因此不会出错。但使用SUID是有安全风险的,本例中的程序并没有能力影响除了wr.log之外的系统环境,但如果是一个包含很多功能的命令(如mount ip等),对该命令授予使用某个用户的完整权限,很大程度上有权限泄露的风险,因此对文件设置SUID时需要谨慎。

[userTest2@localhost userTest1]$ ./getIds real_user_id=10001, effictive_user_id=10000, saved_user_id=10000 real_group_id=20001, effictive_group_id=20001, saved_group_id=20001

更多关于RUID EUID和SUID的内容参见深刻理解——real user id, effective user id, saved user id in Linux

3|0使用capabilities解决上述问题

在linux内核2.2版本之后将基于用户的权限进行了划分,称为capabilities,capabilities是线程相关的,使用时需要在线程上进程设置(完整的capabilities介绍参见capabilities)。那么如何以capabilities解决上述的问题呢?一个简单的办法是改变wr.log的用户和组,这样就不会出现权限问题

对getIds.c做一个小改动增加一行修改wr.log的用户和用户组的操作,其中10001为usetTest2对应的UID,20001为userTest2对应的GID

#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { uid_t ruid; uid_t euid; uid_t suid; getresuid(&ruid, &euid, &suid); printf("real_user_id=%d, effictive_user_id=%d, saved_user_id=%d ",ruid,euid,suid); uid_t rgid; uid_t egid; uid_t sgid; getresgid(&rgid, &egid, &sgid); printf("real_group_id=%d, effictive_group_id=%d, saved_group_id=%d ",rgid,egid,sgid); chown("/home/userTest1/wr.log", 10001, 20001); FILE *stream; stream = fopen( "wr.log", "a+" ); fprintf( stream, "%s", "hello" ); fclose( stream ); return 0; }

编译上述文件,并使用root用户在userTest1目录下设置getIds1拥有修改文件用户和组的权限CAP_CHOWN,+ep代表将该权限添加到capabilities的Effective和Permitted集合中(下面介绍),

[root@localhost userTest1]# setcap cap_chown+ep getIds1

在userTest2下执行getIds可以看到可以执行成功,注意到wr.log的用户和组也被修改为了userTest2的用户和组

[userTest2@localhost userTest1]$ ./getIds1 real_user_id=10001, effictive_user_id=10001, saved_user_id=10001 real_group_id=20001, effictive_group_id=20001, saved_group_id=20001 [userTest2@localhost userTest1]$ ll -rwxrwxrwx. 1 userTest1 root 8712 Dec 13 18:50 getIds -rwxr-xr-x. 1 root root 8760 Dec 13 20:08 getIds1-rw-r--r--. 1 userTest2 newGrp3 30 Dec 13 20:09 wr.log

查看getIds的capabilities,可以看到与设置的一样。最终程序能够运行的原理其实是一样的,即程序的EUID和文件的EUID是一样的。

[userTest2@localhost userTest1]$ getcap getIds1 getIds1 = cap_chown+ep

更简单的办法是给chown设置capabilities,这样进程执行的时候会获取chown上的capabilities,这样就可以拥有权限去执行。在host上执行下面命令。切换到userTest2时就可以使用chown命令直接修改用户和组。此处不能通过给bash设置cap_chow capabilities来操作,因此此时是非root用户,bash进程在执行chown命令的时候会丢掉所有capabilities,导致缺少capabilities而无法运行

# setcap cap_chown=eip /bin/chown
原文地址:https://www.cnblogs.com/dream397/p/13995995.html