(转) Linux的capability深刻分析(2)

一)capability的工具介绍node

 
在咱们的试验环境是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.\n");
                exit(1);
        }
        strcpy(string, "Hello, world!\n");
        length = strlen(string);
        if ((res = write(handle, string, length)) != length)
        {
                printf("Error writing to the file.\n");
                exit(1);
        }
        printf("Wrote %d bytes to the file.\n", 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\n",
                        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\n",
                        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\n", *(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\n", 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\n", 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\n",
(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 \n", (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\n");
                        break;
                case F_WRLCK:
                        printf("Write lease\n");
                        break;
                case F_UNLCK:
                        printf("No leases\n");
                        break;
                default:
                        printf("Some shit\n");
                        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 容许在指定的程序上受权能力给其它程序
相关文章
相关标签/搜索