(轉) 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 容許在指定的程序上受權能力給其它程序
相關文章
相關標籤/搜索