zoukankan      html  css  js  c++  java
  • (转) Linux的capability深入分析(2)

    一)capability的工具介绍

     
    在我们的试验环境是RHEL6,libcap-2.16软件包中包含了相关的capability设置及查看工作,如下:
     
    rpm -ql libcap-2.16-5.2.el6.i686 
    /lib/libcap.so.2
    /lib/libcap.so.2.16
    /lib/security/pam_cap.so
    /usr/sbin/capsh
    /usr/sbin/getcap
    /usr/sbin/getpcaps
    /usr/sbin/setcap
    /usr/share/doc/libcap-2.16
    /usr/share/doc/libcap-2.16/License
    /usr/share/doc/libcap-2.16/capability.notes
    /usr/share/man/man8/getcap.8.gz
    /usr/share/man/man8/setcap.8.gz
     
    getcap可以获得程序文件所具有的能力(CAP).
    getpcaps可以获得进程所具有的能力(CAP).
    setcap可以设置程序文件的能力(CAP).
    我们下面主要用setcap来进行调试.
     
     
    二)CAP_CHOWN 0(允许改变文件的所有权)
     
    授权普通用户可以用/bin/chown程序更改任意文件的owner,如下:
    setcap cap_chown=eip /bin/chown 
     
    查看/bin/chown程序的能力值,如下:
    getcap /bin/chown               
    /bin/chown = cap_chown+eip
     
    切换到test用户,将/bin/ls程序的owner改为test,如下:
    su - test
    chown test.test /bin/ls
     
    ls -l /bin/ls
    -rwxr-xr-x. 1 test test 118736 Jun 14  2010 /bin/ls
     
    注:
    1)cap_chown=eip是将chown的能力以cap_effective(e),cap_inheritable(i),cap_permitted(p)三种位图的方式授权给相关的程序文件.
    2)如果改变文件名,则能力保留到新文件.
    3)用setcap -r /bin/chown可以删除掉文件的能力.
    4)重新用setcap授权将覆盖之前的能力. 
     
     
    三)CAP_DAC_OVERRIDE 1(忽略对文件的所有DAC访问限制)
     
    授权普通用户可以用/usr/bin/vim程序修改所有文件的内容,如下:
    setcap cap_dac_override=eip /usr/bin/vim 
     
    切换到普通用户
    su - test
     
    修改/etc/shadow文件内容
    vim /etc/shadow
    root:$6$3hJf.BoIVU/cdLKb$JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:15094:0:99999:7:::
    bin:*:14790:0:99999:7:::
    daemon:*:14790:0:99999:7:::
    adm:*:14790:0:99999:7:::
     
    注:
    DAC_OVERRIDE能力是DAC_READ_SEARCH能力的超集.
     
     
     
    四)CAP_DAC_READ_SEARCH 2(忽略所有对读、搜索操作的限制)
     
    授权普通用户可以用/bin/cat程序查看所有文件的内容,如下:
    setcap cap_dac_read_search=eip /bin/cat
     
    切换到普通用户
    su - test
     
    查看/etc/shadow,如下:
    cat /etc/shadow
    root:$6$3hJf.BoIVU/cdLKb$JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:15094:0:99999:7:::
    bin:*:14790:0:99999:7:::
    daemon:*:14790:0:99999:7:::
    adm:*:14790:0:99999:7:::
     
     
     
    五)CAP_FOWNER 3(以最后操作的UID,覆盖文件的先前的UID)
     
     
    cp /etc/passwd /tmp/
    ls -l /tmp/passwd   
    -rw-r--r-- 1 root root 1171 2011-04-29 19:21 /tmp/passwd
     
    授权cap_fowner权限给/usr/bin/vim
    setcap cap_fowner=eip /usr/bin/vim
     
    切换到test用户
    su - test
     
    编辑/tmp/passwd文件,存盘退出.
    vi /tmp/passwd
    修改文件,并保存退出.
     
     
    查看/tmp/passwd,发现owner已经变成test
    -rw-r--r-- 1 test test 1176 2011-04-29 19:21 /tmp/passwd
     
     
     
    六)CAP_FSETID 4(确保在文件被修改后不修改setuid/setgid位)
    起因是当文件被修改后,会清除掉文件的setuid/setgid位,而设定CAP_FSETID后将保证setuid/setgid位不被清除.但这对chown函数无用.
     
    测试程序如下:
    #include <sys/types.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    main()
    {
            int handle;
            char string[40];
            int length, res;
     
            if ((handle = open("/tmp/passwd", O_WRONLY | O_CREAT | O_TRUNC,S_IREAD | S_IWRITE)) == -1)
            {
                    printf("Error opening file. ");
                    exit(1);
            }
            strcpy(string, "Hello, world! ");
            length = strlen(string);
            if ((res = write(handle, string, length)) != length)
            {
                    printf("Error writing to the file. ");
                    exit(1);
            }
            printf("Wrote %d bytes to the file. ", res);
            close(handle);
    }
    gcc fsetid.c -o fsetid
     
    先测试没有设FSETID的情况,如下:
    chmod 6777 /tmp/passwd
    ls -l /tmp/passwd
    -rwsrwsrwx 1 test test 14 2011-04-30 14:22 /tmp/passwd
    /tmp/fsetid 
    Wrote 14 bytes to the file.
    ls -l /tmp/passwd
    -rwxrwxrwx 1 test test 14 2011-04-30 14:25 /tmp/passwd
    我们看到setuid/setgid位被清除了.
     
    下面是设定FSETID,如下:
    chmod 6777 /tmp/passwd
    ls -l /tmp/passwd     
    -rwsrwsrwx 1 test test 14 2011-04-30 14:25 /tmp/passwd
     
    切换到root用户,给/tmp/fsetid程序授权CAP_FSETID能力,如下:
    setcap cap_fsetid=eip /tmp/fsetid
     
    切换到普通用户
    /tmp/fsetid
    Wrote 14 bytes to the file.
    ls -l /tmp/passwd
    -rwsrwsrwx 1 test test 14 2011-04-30 14:28 /tmp/passwd
     
     
     
     
     
    七)CAP_KILL 5 (允许对不属于自己的进程发送信号)
     
     
    我们先模拟没有加CAP_KILL能力的情况,如下:
     
    终端1,用root用户启用top程序,如下:
    su - root
    top
     
    终端2,用test用户kill之前的top进程,如下:
    pgrep top     
    3114
    /bin/kill 3114
    kill: Operation not permitted
    我们发现无法对不属于自己的进程发送信号.
     
     
    下面我们用CAP_KILL能力的程序向不属于自己的进程发送信号,如下:
     
    设定kill命令的kill位,如下:
    setcap cap_kill=eip /bin/kill 
     
    杀掉3114进程,没有问题,如下:
    /bin/kill 3114
    echo $?
    0
     
    注意:
    普通用户要用/bin/kill这种绝对路径的方式,而不能用kill这种方式.
     
     
     
    八)CAP_SETGID 6 (设定程序允许普通用户使用setgid函数,这与文件的setgid权限位无关)
     
     
    cp /etc/shadow /tmp/
    chown root.root /tmp/shadow
    chmod 640 /tmp/shadow
     
    切换到普通用户test,并编写setgid测试程序,如下:
    su - test
    #include <unistd.h>
    int
    main ()
    {
            gid_t gid = 0;
            setgid(gid);
            system("/bin/cat /tmp/shadow");
            return 0;
    }
    gcc setgid.c -o setgid
     
    更改setgid程序为CAP_SETGID
    setcap cap_setgid=eip /tmp/setgid
     
    切换到普通用户,运行/tmp/setgid程序,如下:
    su - test
    /tmp/setgid 
    root:$1$S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:14479:0:99999:7:::
    daemon:*:14479:0:99999:7:::
    bin:*:14479:0:99999:7:::
    sys:*:14479:0:99999:7:::
    sync:*:14479:0:99999:7:::
    games:*:14479:0:99999:7:::
    man:*:14479:0:99999:7:::
    lp:*:14479:0:99999:7:::
    mail:*:14479:0:99999:7:::
    news:*:14479:0:99999:7:::
    uucp:*:14479:0:99999:7:::
    proxy:*:14479:0:99999:7:::
    www-data:*:14479:0:99999:7:::
    backup:*:14479:0:99999:7:::
    list:*:14479:0:99999:7:::
     
    我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETGID则使程序不能拥有setgid的权限,如下:
    setcap -r /tmp/setgid
     
    su - test
    /tmp/setgid 
    /bin/cat: /tmp/shadow: Permission denied
     
     
     
     
    九)CAP_SETUID 7 (设定程序允许普通用户使用setuid函数,这也文件的setuid权限位无关)
     
     
    cp /etc/shadow /tmp/
    chown root.root /tmp/shadow
    chmod 640 /tmp/shadow
     
    切换到普通用户test,并编写setuid测试程序,如下:
    su - test
    cd /tmp/
    vi setuid.c
    #include <unistd.h>
    int
    main ()
    {
            uid_t uid = 0;
            setuid(uid);
            system("/bin/cat /tmp/shadow");
            return 0;
    }
    gcc setuid.c -o setuid
     
    切换到root用户,更改setuid程序为CAP_SETUID
    su - root
    setcap cap_setuid=eip /tmp/setuid
     
    切换到test用户,运行/tmp/setuid程序,如下:
    su - test
    /tmp/setuid
    root:$1$S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:14479:0:99999:7:::
    daemon:*:14479:0:99999:7:::
    bin:*:14479:0:99999:7:::
    sys:*:14479:0:99999:7:::
    sync:*:14479:0:99999:7:::
    games:*:14479:0:99999:7:::
    man:*:14479:0:99999:7:::
    lp:*:14479:0:99999:7:::
     
    我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETUID则使程序不能拥有setuid的权限,如下:
     
    setcap -r /tmp/setuid
     
    su - test
    /tmp/setuid 
    /bin/cat: /tmp/shadow: Permission denied
     
     
     
     
    十)CAP_SETPCAP 8 (允许向其它进程转移能力以及删除其它进程的任意能力)
    事实上只有init进程可以设定其它进程的能力,而其它程序无权对进程授权,root用户也不能对其它进程的能力进行修改,只能对当前进程通过cap_set_proc等函数进行修改,而子进程也会继承这种能力.
    所以即使使用了CAP_SETPCAP能力,也不会起到真正的作用.
     
     
     
     
    十一)CAP_LINUX_IMMUTABLE 9 (允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性)
    普通用户不能通过chattr对文件设置IMMUTABLE(chattr +i)和APPEND-ONLY(chattr +a)权限,而通过CAP_LINUX_IMMUTABLE可以使普通用户通过自己增减(immutable/append-only)权限.
     
     
     
    普通用户通过chattr给文件增加immutable权限,如下:
    touch /tmp/test
    chattr +i /tmp/test
    chattr: Operation not permitted while setting flags on /tmp/test
     
    我们看到授权失败了,而如果我们对chattr增加了LINUX_IMMUTABLE权限,则可以成功,如下:
    此时切换到root用户:
    su - 
    setcap cap_linux_immutable=eip /usr/bin/chattr 
     
    切换到普通用户:
    su - test
    chattr +i /tmp/test
    lsattr /tmp/test 
    ----i-------------- /tmp/test
    我们看到授权成功了,注意,这里只能对自己的文件授权(immutable/append-only)权限,对于其它用户的权限LINUX_IMMUTABLE不起作用(root除外),如下:
    su - test
    chattr +i /etc/passwd
    chattr: Permission denied while setting flags on /etc/passwd
     
     
     
     
    十二)CAP_NET_BIND_SERVICE 10(允许绑定到小于1024的端口)
    普通用户不能通过bind函数绑定小于1024的端口,而root用户可以做到,CAP_NET_BIND_SERVICE的作用就是让普通用户也可以绑端口到1024以下.
     
    普通用户通过nc绑定端口500,如下:
    nc -l -p 500
    Can't grab 0.0.0.0:500 with bind : Permission denied
     
    增加CAP_NET_BIND_SERVICE能力到nc程序,如下:
    setcap cap_net_bind_service=eip /usr/bin/nc
     
    再切换到普通用户,通过nc绑定端口500,如下:
    nc -l -p 500
     
    查看该端口:
    netstat -tulnp|grep nc
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      2523/nc       
     
     
     
     
    十三)CAP_NET_BROADCAST 11(允许网络广播和多播访问)
     
    事实上它并没有被应用,普通用户也可以使用ping -b 192.168.0.255也发送广播包
     
     
     
     
    十四)CAP_NET_ADMIN 12(允许执行网络管理任务:接口,防火墙和路由等)
     
    普通用户不能创建新的网络接口(interface),不能更改ip地址,而CAP_NET_ADMIN可以帮助普通用户完成这项工作,如下:
     
    用普通用户创建新的网卡接口eth0:1失败
    /sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
    SIOCSIFADDR: Permission denied
    SIOCSIFFLAGS: Permission denied
    SIOCSIFNETMASK: Permission denied
     
    此时我们把CAP_NET_ADMIN能力授权给ifconfig程序,如下:
    setcap cap_net_admin=eip /sbin/ifconfig
     
    我们再次用普通用户即可以新建网络接口eth0:1,并可以DOWN掉接口,如下:
    /sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
    /sbin/ifconfig eth0:1
    eth0:1    Link encap:Ethernet  HWaddr 00:0c:29:f9:5e:06  
              inet addr:172.16.27.133  Bcast:172.16.27.255  Mask:255.255.255.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              Interrupt:18 Base address:0x1080 
     
    /sbin/ifconfig eth0:1 down 
     
    同样CAP_NET_ADMIN可以让普通用户增加/删除路由,如下:
    /sbin/route add -host 192.168.27.139 gw 192.168.27.2
    SIOCADDRT: Operation not permitted
     
    授权NET_ADMIN,如下:
    setcap cap_net_admin=eip /sbin/route
     
    再次用普通用户增加路由,如下:
    /sbin/route add -host 192.168.27.139 gw 192.168.27.2
    /sbin/route  -n
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    192.168.27.139  192.168.27.2    255.255.255.255 UGH   0      0        0 eth0
    192.168.27.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
    0.0.0.0         192.168.27.2    0.0.0.0         UG    0      0        0 eth0
    /sbin/route del -host 192.168.27.139 gw 192.168.27.2   
     
    我们看到我们除了可以增加路由之外,也可以删除路由.
     
    最后NET_ADMIN可以帮助我们让普通用户来管理防火墙.
    普通用户不能用iptables来管理防火墙,如下:
    /sbin/iptables -L -n
    iptables v1.4.2: can't initialize iptables table `filter': Permission denied (you must be root)
    Perhaps iptables or your kernel needs to be upgraded.
     
    我们将CAP_NET_ADMIN授权给iptables程序,注意我们也要将CAP_NET_RAW授权给iptables,CAP_NET_RAW我们后面再解释,如下:
    setcap cap_net_admin,cap_net_raw=eip /sbin/iptables-multi
     
    此时就可以用普通用户来管理防火墙了,如下:
    /sbin/iptables -A INPUT -p tcp -j ACCEPT
    /sbin/iptables -L -n
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination         
    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           
     
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination         
     
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination     
     
    我们也可以删除防火墙策略,并清空当前的数据流量,如下:
    /sbin/iptables -F
    /sbin/iptables -Z
    /sbin/iptables -X
     
     
     
     
    十五)CAP_NET_RAW 13 (允许使用原始(raw)套接字)
    原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对监控网络流量和分析是很有作用的.
     
    最常见的就是ping的实现,如下:
    socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
     
     
    我们先把ping的setuid权限去掉
    chmod u-s /bin/ping
    ls -l /bin/ping
    -rwxr-xr-x 1 root root 30788 2007-12-09 23:03 /bin/ping
     
    用普通用户使用ping
    ping  192.168.27.2  
    ping: icmp open socket: Operation not permitted
     
    提示没有权限,我们将ping授权CAP_NET_RAW能力,如下:
    setcap cap_net_raw=eip /bin/ping
     
    切换到普通用户再次ping 192.168.27.2,发现可以ping通,如下:
    ping  192.168.27.2
    PING 192.168.27.2 (192.168.27.2) 56(84) bytes of data.
    64 bytes from 192.168.27.2: icmp_seq=1 ttl=128 time=0.266 ms
    64 bytes from 192.168.27.2: icmp_seq=2 ttl=128 time=0.280 ms
    64 bytes from 192.168.27.2: icmp_seq=3 ttl=128 time=0.319 ms
     
    NET_RAW也同样用于tcpdump/iftop,一个普通用户无法使用tcpdump/iftop,而CAP_NET_RAW可以解决这个问题,方式同ping一样,所以我们不做演示.
     
     
     
     
    十六)CAP_IPC_LOCK 14 (在允许锁定内存片段)
    root和普通用户都可以用mlock来锁定内存,区别是root不受ulimit下的锁定内存大小限制,而普通用户会受到影响.
     
    测试程序如下:
    #include <stdio.h>
    #include <sys/mman.h>
     
    int main(int argc, char* argv[])
    {
            int array[2048];
     
            if (mlock((const void *)array, sizeof(array)) == -1) {
                    perror("mlock: ");
                    return -1;
            }
     
            printf("success to lock stack mem at: %p, len=%zd ",
                            array, sizeof(array));
     
     
            if (munlock((const void *)array, sizeof(array)) == -1) {
                    perror("munlock: ");
                    return -1;
            }
     
            printf("success to unlock stack mem at: %p, len=%zd ",
                            array, sizeof(array));
     
            return 0;
    }
    gcc mlock.c -o mlock
     
    切换到普通用户,我们看到mlock是不受限制
    ulimit -a
    max locked memory       (kbytes, -l) unlimited
     
    我们运行程序
    ./mlock
    success to lock stack mem at: 0xbfd94914, len=8192
    success to unlock stack mem at: 0xbfd94914, len=8192
     
     
    我们将限制改为1KB,再次运行程序,如下:
    ulimit -l 1
    ./mlock
    mlock: : Cannot allocate memory
     
    切换到root用户,将CAP_IPC_LOCK能力授权给mlock测试程序,如下:
    setcap cap_ipc_lock=eip /tmp/mlock
     
    用普通用户再次运行程序,执行成功:
    ./mlock
    success to lock stack mem at: 0xbfec1584, len=8192
    success to unlock stack mem at: 0xbfec1584, len=8192
     
     
     
     
     
    十七)CAP_IPC_OWNER 15 (忽略IPC所有权检查)
    这个能力对普通用户有作用,如果用root用户创建共享内存(shmget),权限为600,而普通用户不能读取该段共享内存.
    通过CAP_IPC_OWNER可以让普通用户的程序可以读取/更改共享内存.
     
    我们用下面的程序创建共享内存段,并写入0xdeadbeef到共享内存段中.
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/wait.h>
     
    void error_out(const char *msg)
    {
            perror(msg);
            exit(EXIT_FAILURE);
    }
     
     
    int main (int argc, char *argv[])
    {
            key_t mykey = 12345678;
     
            const size_t region_size = sysconf(_SC_PAGE_SIZE);
            int smid = shmget(mykey, region_size, IPC_CREAT|0600);
            if(smid == -1)
                    error_out("shmget");
     
            void *ptr;
            ptr = shmat(smid, NULL, 0);
            if (ptr == (void *) -1)
                    error_out("shmat");
            u_long *d = (u_long *)ptr;
            *d = 0xdeadbeef;
            printf("ipc mem %#lx ", *(u_long *)ptr);
     
            return 0;
    }
     
    gcc test.c -o test -lrt
    我们用root用户来执行本程序,创建共享内存,如下:
    /tmp/test
    ipc mem 0xdeadbeef
     
    查看当前的共享内存
    ipcs -m
     
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00bc614e 458752     root      600        4096       0              
     
    修改程序,将*d = 0xdeadbeef;改为*d = 0xffffffff;
    再编译,用普通用户运行程序,如下:
    gcc test.c -o test -lrt
     
    su - test
    /tmp/test
    shmget: Permission denied
    我们看到没有权限更改共享内存.
     
    用root用户把CAP_IPC_OWNER能力授权给test程序,如下:
    setcap cap_ipc_owner=eip /tmp/test
     
    再次用普通用户运行程序test,更改共享内存,如下:
    /tmp/test
    ipc mem 0xffffffff
     
    我们看到修改成功,但要说明CAP_IPC_OWNER不能让进程/程序删除/脱离共享内存
     
     
     
     
     
    十八)CAP_SYS_MODULE 16 (允许普通用户插入和删除内核模块)
    由于普通用户不能插入/删除内核模块,而CAP_SYS_MODULE可以帮助普通用户做到这点
     
    例如,用户test插入内核模块nvram
     
    /sbin/modprobe nvram      
    FATAL: Error inserting nvram (/lib/modules/2.6.38.4/kernel/drivers/char/nvram.ko): Operation not permitted
     
    系统提示权限不足.
     
    我们把CAP_SYS_MODULE能力授权给modprobe程序,如下:
    setcap cap_sys_module=eip /sbin/modprobe
     
     
    再用普通用户加载内核模块,如下:
    /sbin/modprobe nvram
    lsmod |grep nvram
    nvram                   3861  0 
    我们看到可以加载.
     
    同样我们可以将CAP_SYS_MODULE授权给rmmod程序,让其可以删除模块,如下:
    setcap cap_sys_module=eip /sbin/rmmod
     
    su - test
    /sbin/rmmod nvram
    lsmod |grep nvram
     
     
     
     
    十九)CAP_SYS_RAWIO 17 (允许用户打开端口,并读取修改端口数据,一般用ioperm/iopl函数)
     
    ioperm只有低端的[0-0x3ff] I/O端口可被设置,且普通用户不能使用.
    iopl可以用于所有的65536个端口,因此ioperm相当于iopl调用的一个子集.
     
    下面的程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值.
    #include <unistd.h>
    #include <sys/io.h>
     
    #define PORT_ADDR 0x3FF
     
    int main(void)
    {
          int ret;
          char port_val;
          
          /*set r/w permission of all 65536 ports*/
          ret = iopl(3);
          if(ret < 0){
               perror("iopl set error");
               return 0;
          }
     
          port_val = inb(PORT_ADDR);
          printf("Original value of port 0x%x is : %.2x ", PORT_ADDR, port_val);
          
          /*reverse the least significant bit */
     
          outb(port_val^0x01, PORT_ADDR);
          port_val = inb(PORT_ADDR);
          printf("Current value of port 0x%x is : %.2x ", PORT_ADDR, port_val);
          
          /*set r/w permission of  all 65536 ports*/
          
          ret = iopl(0);
          if(ret < 0){
               perror("iopl set error");
               return 0;
          }
          return 0;
    }
     
    编译:
    gcc iopl.c -o iopl
     
    普通用户运行iopl程序,提示没有权限.
    /tmp/iopl 
    iopl set error: Operation not permitted
     
    给程序iopl授权CAP_SYS_RAWIO能力,此时普通用户可以执行iopl程序,如下:
    setcap cap_sys_rawio=eip /tmp/iopl
     
    su - test
    /tmp/iopl 
    Original value of port 0x3ff is : 01
    Current value of port 0x3ff is : 00
    /tmp/iopl 
    Original value of port 0x3ff is : 00
    Current value of port 0x3ff is : 01
     
     
     
     
     
    二十)CAP_SYS_CHROOT 18 (允许使用chroot()系统调用)
     
    普通用户不能通过chroot系统调用更改程式执行时所参考的根目录位置,而CAP_SYS_CHROOT可以帮助普通用户做到这一点.
     
    普通用户使用chroot,如下:
    /usr/sbin/chroot / /bin/bash
    /usr/sbin/chroot: cannot change root directory to /: Operation not permitted
     
    通过root授权CAP_SYS_CHROOT能力给chroot程序,如下:
    capset cap_sys_chroot=eip /usr/sbin/chroot
     
     
    普通用户再次用chroot切换根目录,如下:
    /usr/sbin/chroot / /bin/sh
    sh-3.2$
     
     
     
     
     
    二十一)CAP_SYS_PTRACE 19 (允许跟踪任何进程)
     
    普通用户不能跟踪任何进程,不包括它自己的进程,而CAP_SYS_PTRACE可以帮助普通用户跟踪任何进程.
     
    切换到普通用户,跟踪PID1的进程.
    strace -p 1
    attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
     
    切换到root用户,将CAP_SYS_PTRACE能力授权给strace程序,用于跟踪进程,如下:
    setcap cap_sys_ptrace=eip /usr/bin/strace
     
    切换到普通用户,跟踪PID1的进程,如下:
    strace -p 1
    Process 1 attached - interrupt to quit
    select(11, [10], NULL, NULL, {3, 771381}) = 0 (Timeout)
    time(NULL)                              = 1304348451
    stat64("/dev/initctl", {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
    fstat64(10, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
    stat64("/dev/initctl", {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
    select(11, [10], NULL, NULL, {5, 0})    = 0 (Timeout)
    time(NULL)                              = 1304348456
     
     
     
     
     
    二十二)CAP_SYS_PACCT 20 (允许配置进程记帐process accounting) 
     
    要完成进程记帐,要保证有写入文件的权限,这里我们将进程记录写入到/home/test/log/psacct.
    mkdir /home/test/log/
    touch /home/test/log/psacct
     
     
    程序通过acct函数,将进程的记帐写入到指定文件中,如果acct函数的参数为NULL,则关闭进程记帐.
    #include <stdlib.h>
    #include <sys/acct.h>
     
    int
    main()
    {
            int ret;
            ret = acct("/home/test/log/pacct");
            if(ret < 0){
               perror("acct on error");
               return 0;
            }
            system("/bin/ls -l");
            acct(NULL);
            if(ret < 0){
               perror("acct off error");
               return 0;
            }
            return 0;
    }
    gcc psacct.c -o psacct
     
    ./psacct 
    acct on error: Operation not permitted
     
    给psacct程序授权CAP_SYS_PACCT能力,如下:
    setcap cap_sys_psacct /home/test/psacct
    注意这里的能力是sys_psacct,而不是sys_pacct
     
     
    回到普通用户,执行psacct
    ./psacct 
    total 24
    drwxr-xr-x 2 test test 4096 2011-05-02 13:28 log
    -rw-r--r-- 1 test test   64 2011-05-02 13:25 pacct
    -rwxr-xr-x 1 test test 6590 2011-05-02 13:31 psacct
    -rw-r--r-- 1 test test  314 2011-05-02 13:31 psacct.c
     
    我们看到已经执行成功,下面我们再看下进程记录,如下:
    lastcomm -f /home/test/log/pacct 
    ls                     test     pts/0      0.03 secs Mon May  2 13:33
     
     
     
     
     
    二十三)CAP_SYS_ADMIN 21 (允许执行系统管理任务,如挂载/卸载文件系统,设置磁盘配额,开/关交换设备和文件等)
     
    下面是普通用户拥有相关管理权限的测试
     
     
    1)更改主机名
    setcap cap_sys_admin=eip /bin/hostname
     
    su - test
    hostname test2
    hostname
    test2
     
     
    2)挂载/卸载文件系统
     
    这里我们注意,系统的mount命令不能做这个试验,因为程序中做了判断,如果不是root用户请退出.所以我们用mount()函数来完成这个试验,程序如下:
     
    #include <stdlib.h>
    #include <sys/mount.h>
    int
    main ()
    {
            int ret;
            ret = mount("/dev/sda1", "/mnt/", "ext3", MS_MGC_VAL, NULL);
            if(ret < 0){
               perror("mount error");
               return 0;
            }
            return 0;
    }
     
    用普通用户编译运行:
    gcc mounttest.c -o mounttest
    ./mounttest 
    mount error: Operation not permitted
     
    我们看到普通用户不能完成mount操作,而CAP_SYS_ADMIN可以帮助普通用户完成该操作,如下:
     
    setcap cap_sys_admin=eip /home/test/mounttest 
     
     
    切换到普通用户,执行mounttest程序,如下:
    ./mounttest 
    cat /proc/mounts 
    /dev/sda1 /mnt ext3 rw,relatime,errors=remount-ro,barrier=0,data=writeback 0 0
    umount和mount一样,我们在这里不做演示.
     
     
    3)swapon/swapoff
     
    普通用户不能进行swapon/swapoff操作,而CAP_SYS_ADMIN可以帮助普通用户完成swapon/swapoff操作,如下:
    dd if=/dev/zero of=/tmp/testdb bs=10M count=1
    1+0 records in
    1+0 records out
    10485760 bytes (10 MB) copied, 0.164669 s, 63.7 MB/s
    /sbin/mkswap /tmp/testdb
    Setting up swapspace version 1, size = 10481 kB
    no label, UUID=0ff46dc8-781c-4c3f-81b3-fe860f74793e
    /sbin/swapon /tmp/testdb
    swapon: /tmp/testdb: Operation not permitted
     
    我们看到swapon操作被拒绝,这里我们对swapon进行授权,如下:
    setcap cap_sys_admin /sbin/swapon
     
    普通用户再次swapon,如下:
    /sbin/swapon /tmp/testdb
    /sbin/swapon 
    /sbin/swapon -s
    Filename                                Type            Size    Used    Priority
    /dev/sda6                               partition       7815584 0       -1
    /tmp/testdb                             file            10236   0       -2
    我们看到swapon操作成功.因为swapoff是swapon的软链接,所以可以直接swapoff掉交换分区,如下:
    /sbin/swapoff /tmp/testdb
    /sbin/swapon -s
    Filename                                Type            Size    Used    Priority
    /dev/sda6                               partition       7815584 0       -1
    ls -l /sbin/swapoff    
    lrwxrwxrwx 1 root root 6 2009-08-23 07:49 /sbin/swapoff -> swapon
     
     
     
     
     
    二十四) CAP_SYS_BOOT 22 (允许普通用使用reboot()函数)
     
    这里我们无法用reboot命令来做测试,因为reboot命令做了判断,只允许root(UID=0)的用户可以使用.
     
    我们用下面的程序进行测试.
    #include <unistd.h>
    #include <sys/reboot.h>
    int main()
    {
        sync(); 
        return reboot(RB_AUTOBOOT);
    }
     
    编译:
    gcc reboot1.c -o reboot1
    ./reboot1
    这时系统没有重启.
     
    我们查看程序的返回码,这里是255,说明程序没有运行成功.
    echo $?
    255
     
    我们用CAP_SYS_BOOT能力使reboot1程序可以被普通用户重启,如下:
    setcap cap_sys_boot=eip /home/test/reboot1
     
    用普通用户再试运行reboot1,如下:
    reboot1
     
    此时系统被重启了.
     
     
     
     
    二十五)CAP_SYS_NICE 23(允许提升优先级,设置其它进程的优先级)
     
    对于普通用户程序的NICE优先级,不能超过ulimit对它的限制,如下:
    nice -n -5 ls 
    nice: cannot set niceness: Permission denied
     
    而CAP_SYS_NICE可以帮助普通用户设置一个想要的一个任意优先级.
    setcap cap_sys_nice=eip /usr/bin/nice
     
    切换到普通用户,指定优先级,如下:
    nice -n -5 ls 
    log  mnt  mount.c  mounttest  pacct  psacct  psacct.c  reboot1  reboot1.c  test
     
    普通用户也不能给指定进程指定NICE优先级,而CAP_SYS_NICE也可以做的,如下:
    renice -5 2255
    renice: 2255: setpriority: Operation not permitted
     
    setcap cap_sys_nice=eip /usr/bin/renice
     
     
    renice -5 2255
    2255: old priority 0, new priority -5
     
    我们甚至可以用CAP_SYS_NICE来指定实时优先级
    chrt -f 50  ls
    chrt: failed to set pid 0's policy: Operation not permitted
     
    给/usr/bin/chrt命令授权CAP_SYS_NICE能力,如下:
    setcap  cap_sys_nice=eip  /usr/bin/chrt
     
    切换到普通用户,如下:
    chrt -f 50  ls
    log  mnt  setulimit  setulimit.c
     
    我们也可以指定它的CPU亲和性,如下:
    taskset -p 1 2255
    pid 2255's current affinity mask: 1
    sched_setaffinity: Operation not permitted
    failed to set pid 2255's affinity.
     
    给/usr/bin/taskset命令授权CAP_SYS_NICE能力,如下:
    setcap  cap_sys_nice=eip  /usr/bin/taskset
     
    切换到普通用户,再次运行taskset,可以成功的设置CPU亲和性
    taskset -p 1 2255
    pid 2255's current affinity mask: 1
    pid 2255's new affinity mask: 1
     
     
     
     
     
    二十六) CAP_SYS_RESOURCE 24 忽略资源限制
     
    普通用户不能用setrlimit()来突破ulimit的限制
     
    我们用下面的程序进行测试,普通用户是无法修改RLIMIT_STACK(堆栈大小)的.如下:
     
    #include <signal.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/resource.h>
     
    int
    main (int argc, char *argv[])
    {
    int r = 0;
    struct rlimit rl;
     
    getrlimit (RLIMIT_STACK,&rl);
     
    printf("crrent hard limit is %ld ",
    (u_long) rl.rlim_max);
     
    rl.rlim_max = rl.rlim_max+1;
    r = setrlimit (RLIMIT_STACK, &rl);
    if (r){
    perror("setrlimit");
    return -1;
    }
     
    printf("limit set to %ld ", (u_long) rl.rlim_max+1);
    return 0;
    }
     
    gcc setulimit.c -o setulimit
     
    我们先来查看当前的限制,这里是10MB,如下:
    ulimit -H -s 
    10240
     
    ./setulimit    
    crrent hard limit is 10485760
    setrlimit: Operation not permitted
     
    我们给setulimit程序以CAP_SYS_RESOURCE的能力,如下:
    setcap cap_sys_resource=eip /home/test/setulimit 
     
    用普通用户再次运行程序,已经可以通过setrlimit()设定超过限额了,如下:
    ./setulimit 
    crrent hard limit is 10485760
    limit set to 10485762 
     
     
    同样我们也可以用CAP_SYS_RESOURCE能力使程序超出磁盘限额,如下:
     
    quotacheck -avug
     
    quotaon -avug
     
    edquota -u test
     
    Filesystem                   blocks       soft       hard     inodes     soft     hard
      /dev/sda7                         0          3          5          0        0        0
     
    mkdir /export/test
    chown -R test.test /export/test/
     
    切换到普通用户,用dd命令产生3MB的文件,这明显超过了5kb的限制,如下:
    su - test
    dd if=/dev/zero of=/export/test/test bs=1M count=3
    sda7: warning, user block quota exceeded.
    sda7: write failed, user block limit reached.
    dd: writing `test': Disk quota exceeded
    1+0 records in
    0+0 records out
    4096 bytes (4.1 kB) copied, 0.0117371 s, 349 kB/s
     
    授权CAP_SYS_RESOURCE能力给/bin/dd命令,如下:
    setcap cap_sys_resource=eip /bin/dd
     
     
    再次用普通用户运行dd命令,即可以超过5kb的限额了.
    su - test
    dd if=/dev/zero of=test bs=1M count=3
    sda7: warning, user block quota exceeded.
    3+0 records in
    3+0 records out
    3145728 bytes (3.1 MB) copied, 0.423662 s, 7.4 MB/s
     
     
     
     
     
    二十七)CAP_SYS_TIME 25(允许改变系统时钟)
     
    普通用户不能改变系统时钟,如下:
    date -s 2012-01-01
    date: cannot set date: Operation not permitted
    Sun Jan  1 00:00:00 EST 2012
     
    CAP_SYS_TIME可以帮助普通用户改变系统时钟,如下:
    setcap cap_sys_time=eip /bin/date
     
    切换到普通用户再次改变时间,发现已经可以改变了
    su - test
    date -s 2012-01-01
    Sun Jan  1 00:00:00 EST 2012
    date
    Sun Jan  1 00:00:02 EST 2012
     
     
     
     
     
    二十八)CAP_SYS_TTY_CONFIG 26(允许配置TTY设备)
     
    我们下面用vhangup()函数来挂起当前的tty
    程序如下:
    #include <stdio.h>
    #include <unistd.h>
     
    int main ()
    {
      int r;
      r=vhangup();
      if (r){ 
      perror ("vhanguo");
      }
      return 0;
    }
     
    gcc vhup.c -o vhup
     
    ./vhup 
    vhanguo: Operation not permitted
     
    我们给vhup程序设定CAP_SYS_TTY_CONFIG能力,如下:
    setcap cap_sys_tty_config=eip /home/test/vhup
     
     
    再次用普通用户执行程序vhup,tty被挂起,如下:
    ./vhup 
    此时当前tty被挂起.
     
     
     
     
    二十九) CAP_MKNOD 27 (允许使用mknod系统调用)
     
    普通用户不能用mknod()来创建设备文件,而CAP_MKNOD可以帮助普通用户做到这一点,如下:
    mknod /tmp/tnod1 c 1 5
    mknod: `/tmp/tnod1': Operation not permitted
     
    setcap cap_mknod=eip /bin/mknod
     
     
    切换到普通用户,再次用mknod命令创建设备文件,如下:
    mknod /tmp/tnod1 c 1 5
    ls -l /tmp/tnod1 
    crw-r--r-- 1 test test 1, 5 2012-01-01 00:31 /tmp/tnod1
     
     
     
     
    三十) CAP_LEASE 28(允许在文件上建立租借锁)
     
    系统调用fcntl()可以用于租借锁,此时采用的函数原型如下:
           int fcntl(int fd, int cmd, long arg);
     
    与租借锁相关的 cmd 参数的取值有两种:F_SETLEASE 和 F_GETLEASE。其含义如下所示:
    F_SETLEASE:根据下面所描述的 arg 参数指定的值来建立或者删除租约:
    F_RDLCK:设置读租约。当文件被另一个进程以写的方式打开时,拥有该租约的当前进程会收到通知
    F_WRLCK:设置写租约。当文件被另一个进程以读或者写的方式打开时,拥有该租约的当前进程会收到通知
    F_UNLCK:删除以前建立的租约
    F_GETLEASE:表明调用进程拥有文件上哪种类型的锁,这需要通过返回值来确定,返回值有三种:F_RDLCK、F_WRLCK和F_UNLCK,分别表明调用进程对文件拥有读租借、写租借或者根本没有租借
    某个进程可能会对文件执行其他一些系统调用(比如 OPEN() 或者 TRUNCATE()),如果这些系统调用与该文件上由 F_SETLEASE 所设置的租借锁相冲突,内核就会阻塞这个系统调用;
    同时,内核会给拥有这个租借锁的进程发信号,告知此事。拥有此租借锁的进程会对该信号进行反馈,它可能会删除这个租借锁,也可能会减短这个租借锁的租约,从而可以使得该文件可以被其他进程所访问。
    如果拥有租借锁的进程不能在给定时间内完成上述操作,那么系统会强制帮它完成。通过 F_SETLEASE 命令将 arg 参数指定为 F_UNLCK 就可以删除这个租借锁。
    不管对该租借锁减短租约或者干脆删除的操作是进程自愿的还是内核强迫的,只要被阻塞的系统调用还没有被发出该调用的进程解除阻塞,那么系统就会允许这个系统调用执行。
    即使被阻塞的系统调用因为某些原因被解除阻塞,但是上面对租借锁减短租约或者删除这个过程还是会执行的。
     
    源程序如下:
    #define _GNU_SOURCE 
     
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <sys/file.h>
    static void show_lease(int fd)
    {
            int res;
     
            res = fcntl(fd, F_GETLEASE);
            switch (res) {
                    case F_RDLCK:
                            printf("Read lease ");
                            break;
                    case F_WRLCK:
                            printf("Write lease ");
                            break;
                    case F_UNLCK:
                            printf("No leases ");
                            break;
                    default:
                            printf("Some shit ");
                            break;
            }
    }
     
    int main(int argc, char **argv)
    {
            int fd, res;
     
            fd = open(argv[1], O_RDONLY);
            if (fd == -1) {
                    perror("Can't open file");
                    return 1;
            }
     
            res = fcntl(fd, F_SETLEASE, F_WRLCK);
            if (res == -1) {
                    perror("Can't set lease");
                    return 1;
            }
     
            show_lease(fd);
     
            if (flock(fd, LOCK_SH) == -1) {
                    perror("Can't flock shared");
                    return 1;
            }
     
            show_lease(fd);
     
            return 0;
    }
     
    编译:
    gcc fcntl.c -o fcntl
     
    我们使用普通用户在/etc/passwd文件上建立租借锁,由于普通用户没有/etc/passwd上建租借锁的权限,故而报错,如下:
    su - test
    /tmp/fcntl /etc/passwd
    Can't set lease: Permission denied
     
    注:
    普通用户可以在自己的文件上(owner)建立租借锁.
     
    授权lease给/tmp/fcntl文件,如下:
    setcap cap_lease=eip /tmp/fcntl
     
     
    再次运行/tmp/fcntl,可以建立租借锁了,如下:
    /tmp/fcntl /etc/passwd
    Write lease
    Write lease
     
     
     
    三十一)CAP_SETFCAP 31 (允许在指定的程序上授权能力给其它程序)
     
    例如我们让普通用户也能用setcap给其它程序授权,如下:
    setcap CAP_SETFCAP=eip /usr/sbin/setcap 
     
    su - test
    setcap CAP_SETPCAP=eip /bin/ls
     
    getcap /bin/ls                
    /bin/ls = cap_setpcap+eip
     
     
    三十二)其它的能力
    CAP_AUDIT_WRITE
    CAP_AUDIT_CONTROL
    CAP_MAC_OVERRIDE
    CAP_MAC_ADMIN
    CAP_SYSLOG
    这五组只能涉及到syslog,audit,mac等安全模块,以后专门对其进行分析.
     
     
     
    三十三)总结:
    CAP_CHOWN 0 允许改变文件的所有权 
    CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制 
    CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制 
    CAP_FOWNER 3 以最后操作的UID,覆盖文件的先前的UID
    CAP_FSETID 4 确保在文件被修改后不修改setuid/setgid位
    CAP_KILL 5 允许对不属于自己的进程发送信号 
    CAP_SETGID 6 允许改变组ID 
    CAP_SETUID 7 允许改变用户ID 
    CAP_SETPCAP 8 允许向其它进程转移能力以及删除其它进程的任意能力(只限init进程)
    CAP_LINUX_IMMUTABLE 9 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性 
    CAP_NET_BIND_SERVICE 10 允许绑定到小于1024的端口 
    CAP_NET_BROADCAST 11 允许网络广播和多播访问(未使用) 
    CAP_NET_ADMIN 12 允许执行网络管理任务:接口、防火墙和路由等.
    CAP_NET_RAW 13 允许使用原始(raw)套接字 
    CAP_IPC_LOCK 14 允许锁定共享内存片段 
    CAP_IPC_OWNER 15 忽略IPC所有权检查 
    CAP_SYS_MODULE 16 插入和删除内核模块 
    CAP_SYS_RAWIO 17 允许对ioperm/iopl的访问 
    CAP_SYS_CHROOT 18 允许使用chroot()系统调用 
    CAP_SYS_PTRACE 19 允许跟踪任何进程 
    CAP_SYS_PACCT 20 允许配置进程记帐(process accounting) 
    CAP_SYS_ADMIN 21 允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等.
    CAP_SYS_BOOT 22 允许重新启动系统 
    CAP_SYS_NICE 23 允许提升优先级,设置其它进程的优先级 
    CAP_SYS_RESOURCE 24 忽略资源限制 
    CAP_SYS_TIME 25 允许改变系统时钟 
    CAP_SYS_TTY_CONFIG 26 允许配置TTY设备 
    CAP_MKNOD 27 允许使用mknod()系统调用 
    CAP_LEASE 28 允许在文件上建立租借锁
    CAP_SETFCAP 31 允许在指定的程序上授权能力给其它程序
  • 相关阅读:
    Android实战技巧之三十八:Handler使用中可能引发的内存泄漏
    android上FragmentTabHost实现自己定义Tab Indicator
    GSO/TSO/GRO等对VirtIO虚机的网络性能影响分析(by quqi99)
    经典开源作品
    @在php中的作用
    .net开发中常用的第三方组件
    如何正确并完全安装Visual Studio 2015企业版本?
    TinyPNG---一个压缩PNG的神站
    asp.net MD5 加密
    PHP判断访问者手机移动端还是PC端的函数,亲测好用
  • 原文地址:https://www.cnblogs.com/fengwei/p/4520880.html
Copyright © 2011-2022 走看看