Linux的capability深入分析(2)【转】

转自:https://blog.csdn.net/wangpengqi/article/details/9821231



rpm -ql libcap-2.16-5.2.el6.i686 
/lib/libcap.so.2.16
/usr/sbin/capsh
/usr/sbin/getpcaps
/usr/share/doc/libcap-2.16
/usr/share/doc/libcap-2.16/capability.notes
/usr/share/man/man8/setcap.8.gz
 
getpcaps可以获得进程所具有的能力(CAP).
我们下面主要用setcap来进行调试.
 
 

setcap cap_chown=eip /bin/chown 
 
getcap /bin/chown               

su - test

-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)三种位图的方式授权给相关的程序文件.
3)用setcap -r /bin/chown可以删除掉文件的能力.
4)重新用setcap授权将覆盖之前的能力. 
 
 

setcap cap_dac_override=eip /usr/bin/vim 
 
su - test
 
vim /etc/shadow
bin:*:14790:0:99999:7:::
adm:*:14790:0:99999:7:::
 
DAC_OVERRIDE能力是DAC_READ_SEARCH能力的超集.
 
 
 

setcap cap_dac_read_search=eip /bin/cat
 
su - test
 
cat /etc/shadow
bin:*:14790:0:99999:7:::
adm:*:14790:0:99999:7:::
 
 
 

 
ls -l /tmp/passwd   

setcap cap_fowner=eip /usr/bin/vim
 
su - test
 
vi /tmp/passwd

 
-rw-r--r-- 1 test test 1176 2011-04-29 19:21 /tmp/passwd
 
 
 
起因是当文件被修改后,会清除掉文件的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>
{
        int handle;
        char string[40];
        int length, res;
 
        {
                exit(1);
        }
        length = strlen(string);
        if ((res = write(handle, string, length)) != length)
        {
                exit(1);
        }
        close(handle);
gcc fsetid.c -o fsetid
 
chmod 6777 /tmp/passwd
-rwsrwsrwx 1 test test 14 2011-04-30 14:22 /tmp/passwd
/tmp/fsetid 
ls -l /tmp/passwd
我们看到setuid/setgid位被清除了.
 
chmod 6777 /tmp/passwd
ls -l /tmp/passwd     

setcap cap_fsetid=eip /tmp/fsetid
 
/tmp/fsetid
ls -l /tmp/passwd

 
 
 
 

 

su - root

pgrep top     
/bin/kill 3114
我们发现无法对不属于自己的进程发送信号.
 
 

setcap cap_kill=eip /bin/kill 
 
/bin/kill 3114
0
 
普通用户要用/bin/kill这种绝对路径的方式,而不能用kill这种方式.
 
 
 

 
chown root.root /tmp/shadow

su - test
#include <unistd.h>
main ()
        gid_t gid = 0;
        setgid(gid);
        return 0;
gcc setgid.c -o setgid
 
setcap cap_setgid=eip /tmp/setgid
 
su - test
/tmp/setgid 
daemon:*:14479:0:99999:7:::
sys:*:14479:0:99999:7:::
games:*:14479:0:99999:7:::
lp:*:14479:0:99999:7:::
news:*:14479:0:99999:7:::
proxy:*:14479:0:99999:7:::
backup:*:14479:0:99999:7:::

setcap -r /tmp/setgid
 
/tmp/setgid 

 
 
 

 
chown root.root /tmp/shadow

su - test
vi setuid.c
#include <unistd.h>
main ()
        uid_t uid = 0;
        setuid(uid);
        return 0;
gcc setuid.c -o setuid
 
su - root

su - test
root:$1$S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:14479:0:99999:7:::
bin:*:14479:0:99999:7:::
sync:*:14479:0:99999:7:::
man:*:14479:0:99999:7:::



/tmp/setuid 

 
 
 
事实上只有init进程可以设定其它进程的能力,而其它程序无权对进程授权,root用户也不能对其它进程的能力进行修改,只能对当前进程通过cap_set_proc等函数进行修改,而子进程也会继承这种能力.

 
 
 
普通用户不能通过chattr对文件设置IMMUTABLE(chattr +i)和APPEND-ONLY(chattr +a)权限,而通过CAP_LINUX_IMMUTABLE可以使普通用户通过自己增减(immutable/append-only)权限.
 
 
 
touch /tmp/test
chattr: Operation not permitted while setting flags on /tmp/test
 
此时切换到root用户:
su - 
setcap cap_linux_immutable=eip /usr/bin/chattr 
 
su - test
lsattr /tmp/test 
我们看到授权成功了,注意,这里只能对自己的文件授权(immutable/append-only)权限,对于其它用户的权限LINUX_IMMUTABLE不起作用(root除外),如下:
chattr +i /etc/passwd

 
 
 
普通用户不能通过bind函数绑定小于1024的端口,而root用户可以做到,CAP_NET_BIND_SERVICE的作用就是让普通用户也可以绑端口到1024以下.
 
nc -l -p 500

setcap cap_net_bind_service=eip /usr/bin/nc
 
nc -l -p 500
 
netstat -tulnp|grep nc
tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      2523/nc       
 
 
 
 


 
 
 


/sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
SIOCSIFFLAGS: Permission denied

setcap cap_net_admin=eip /sbin/ifconfig
 
/sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
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 
 
/sbin/route add -host 192.168.27.139 gw 192.168.27.2

setcap cap_net_admin=eip /sbin/route
 
/sbin/route add -host 192.168.27.139 gw 192.168.27.2
/sbin/route  -n
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   
 

普通用户不能用iptables来管理防火墙,如下:
iptables v1.4.2: can't initialize iptables table `filter': Permission denied (you must be root)

setcap cap_net_admin,cap_net_raw=eip /sbin/iptables-multi
 
/sbin/iptables -A INPUT -p tcp -j ACCEPT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           
 
target     prot opt source               destination         
 
target     prot opt source               destination     
 
/sbin/iptables -F
/sbin/iptables -X
 
 
 
 
原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对监控网络流量和分析是很有作用的.
 
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
 
 
chmod u-s /bin/ping
-rwxr-xr-x 1 root root 30788 2007-12-09 23:03 /bin/ping
 
ping  192.168.27.2  

setcap cap_net_raw=eip /bin/ping
 
ping  192.168.27.2
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=3 ttl=128 time=0.319 ms
 

 
 
 
root和普通用户都可以用mlock来锁定内存,区别是root不受ulimit下的锁定内存大小限制,而普通用户会受到影响.
 
#include <stdio.h>
#include <sys/mman.h>
 
{
        int array[2048];
 
        if (mlock((const void *)array, sizeof(array)) == -1) {
                return -1;
        }
 
                        array, sizeof(array));
 
 
        if (munlock((const void *)array, sizeof(array)) == -1) {
                return -1;
        }
 
                        array, sizeof(array));
 
        return 0;
gcc mlock.c -o mlock
 
ulimit -a
max locked memory       (kbytes, -l) unlimited
 
./mlock
success to unlock stack mem at: 0xbfd94914, len=8192
 
 
ulimit -l 1
mlock: : Cannot allocate memory
 
setcap cap_ipc_lock=eip /tmp/mlock
 
./mlock
success to unlock stack mem at: 0xbfec1584, len=8192
 
 
 
 
 
这个能力对普通用户有作用,如果用root用户创建共享内存(shmget),权限为600,而普通用户不能读取该段共享内存.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
 
{
        perror(msg);
        exit(EXIT_FAILURE);

 
{
        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)
 
        void *ptr;
        ptr = shmat(smid, NULL, 0);
        if (ptr == (void *) -1)
        u_long *d = (u_long *)ptr;
        *d = 0xdeadbeef;
 
        return 0;

我们用root用户来执行本程序,创建共享内存,如下:
ipc mem 0xdeadbeef
 
ipcs -m
 
key        shmid      owner      perms      bytes      nattch     status      
0x00bc614e 458752     root      600        4096       0              
 
修改程序,将*d = 0xdeadbeef;改为*d = 0xffffffff;
gcc test.c -o test -lrt
 
/tmp/test
我们看到没有权限更改共享内存.
 
setcap cap_ipc_owner=eip /tmp/test
 
/tmp/test


 
 
 
 
由于普通用户不能插入/删除内核模块,而CAP_SYS_MODULE可以帮助普通用户做到这点
 

/sbin/modprobe nvram      


setcap cap_sys_module=eip /sbin/modprobe
 
 
/sbin/modprobe nvram
nvram                   3861  0 

setcap cap_sys_module=eip /sbin/rmmod
 
/sbin/rmmod nvram

 
 
 

iopl可以用于所有的65536个端口,因此ioperm相当于iopl调用的一个子集.
 
#include <unistd.h>
#include <sys/io.h>
 

{
      int ret;
      char port_val;
      
      /*set r/w permission of all 65536 ports*/
      ret = iopl(3);
      if(ret < 0){
           return 0;
      }
 
      port_val = inb(PORT_ADDR);
      
      /*reverse the least significant bit */
 
      outb(port_val^0x01, PORT_ADDR);
      port_val = inb(PORT_ADDR);
      
      /*set r/w permission of  all 65536 ports*/
      
      ret = iopl(0);
      if(ret < 0){
           return 0;
      }
      return 0;

gcc iopl.c -o iopl
 
/tmp/iopl 

setcap cap_sys_rawio=eip /tmp/iopl
 
/tmp/iopl 
Current value of port 0x3ff is : 00
/tmp/iopl 
Current value of port 0x3ff is : 01
 
 
 
 
 


/usr/sbin/chroot / /bin/bash

capset cap_sys_chroot=eip /usr/sbin/chroot
 
 
/usr/sbin/chroot / /bin/sh

 
 
 
 


strace -p 1

setcap cap_sys_ptrace=eip /usr/bin/strace
 
strace -p 1
select(11, [10], NULL, NULL, {3, 771381}) = 0 (Timeout)
time(NULL)                              = 1304348451
fstat64(10, {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) 
 
mkdir /home/test/log/

 
#include <stdlib.h>
#include <sys/acct.h>
 
main()
        int ret;
        if(ret < 0){
           return 0;
        }
        acct(NULL);
        if(ret < 0){
           return 0;
        }
        return 0;
gcc psacct.c -o psacct
 
./psacct 

setcap cap_sys_psacct /home/test/psacct

 
./psacct 
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
-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
 
 
 
 
 


 
setcap cap_sys_admin=eip /bin/hostname
 
hostname test2
test2
 
 


#include <stdlib.h>
#include <sys/mount.h>
main ()
        int ret;
        if(ret < 0){
           return 0;
        }
        return 0;

gcc mounttest.c -o mounttest
./mounttest 


setcap cap_sys_admin=eip /home/test/mounttest 
 
 
./mounttest 
cat /proc/mounts 
/dev/sda1 /mnt ext3 rw,relatime,errors=remount-ro,barrier=0,data=writeback 0 0

 

dd if=/dev/zero of=/tmp/testdb bs=10M count=1
1+0 records out
/sbin/mkswap /tmp/testdb
no label, UUID=0ff46dc8-781c-4c3f-81b3-fe860f74793e
swapon: /tmp/testdb: Operation not permitted
 
setcap cap_sys_admin /sbin/swapon
 
/sbin/swapon /tmp/testdb
/sbin/swapon 
Filename                                Type            Size    Used    Priority
/dev/sda6                               partition       7815584 0       -1
/tmp/testdb                             file            10236   0       -2
/sbin/swapoff /tmp/testdb
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
 
 
 
 
 


#include <unistd.h>
#include <sys/reboot.h>
{
    sync(); 
    return reboot(RB_AUTOBOOT);

gcc reboot1.c -o reboot1
这时系统没有重启.
 
echo $?

setcap cap_sys_boot=eip /home/test/reboot1
 
reboot1
 

 
 
 

nice -n -5 ls 

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
 
renice -5 2255


 
2255: old priority 0, new priority -5
 
chrt -f 50  ls

setcap  cap_sys_nice=eip  /usr/bin/chrt
 
chrt -f 50  ls
log  mnt  setulimit  setulimit.c
 
taskset -p 1 2255
sched_setaffinity: Operation not permitted

setcap  cap_sys_nice=eip  /usr/bin/taskset
 
taskset -p 1 2255
pid 2255's new affinity mask: 1
 
 
 
 
 



#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>
 
main (int argc, char *argv[])
int r = 0;
struct rlimit rl;
 
getrlimit (RLIMIT_STACK,&rl);
 
(u_long) rl.rlim_max);
 
rl.rlim_max = rl.rlim_max+1;
r = setrlimit (RLIMIT_STACK, &rl);
perror("setrlimit");
return -1;

printf("limit set to %ld ", (u_long) rl.rlim_max+1);
return 0;


ulimit -H -s 

./setulimit    
setrlimit: Operation not permitted
 
setcap cap_sys_resource=eip /home/test/setulimit 
 
./setulimit 
limit set to 10485762 
 
 




Filesystem                   blocks       soft       hard     inodes     soft     hard
  /dev/sda7                         0          3          5          0        0        0
 
chown -R test.test /export/test/
 
su - test
sda7: warning, user block quota exceeded.
dd: writing `test': Disk quota exceeded
0+0 records out

setcap cap_sys_resource=eip /bin/dd
 
 
su - test
sda7: warning, user block quota exceeded.
3+0 records out

 
 
 
 

date -s 2012-01-01
Sun Jan  1 00:00:00 EST 2012
 
setcap cap_sys_time=eip /bin/date
 
su - test
Sun Jan  1 00:00:00 EST 2012
Sun Jan  1 00:00:02 EST 2012
 
 
 
 
 

程序如下:
#include <stdio.h>
#include <unistd.h>
 
{
  int r;
  r=vhangup();
  if (r){ 
  }
  return 0;


./vhup 

setcap cap_sys_tty_config=eip /home/test/vhup
 
 
./vhup 

 
 
 

mknod /tmp/tnod1 c 1 5


 
mknod /tmp/tnod1 c 1 5
ls -l /tmp/tnod1 

 
 
 

       int fcntl(int fd, int cmd, long arg);
 
F_SETLEASE:根据下面所描述的 arg 参数指定的值来建立或者删除租约:
F_WRLCK:设置写租约。当文件被另一个进程以读或者写的方式打开时,拥有该租约的当前进程会收到通知
F_GETLEASE:表明调用进程拥有文件上哪种类型的锁,这需要通过返回值来确定,返回值有三种:F_RDLCK、F_WRLCK和F_UNLCK,分别表明调用进程对文件拥有读租借、写租借或者根本没有租借
同时,内核会给拥有这个租借锁的进程发信号,告知此事。拥有此租借锁的进程会对该信号进行反馈,它可能会删除这个租借锁,也可能会减短这个租借锁的租约,从而可以使得该文件可以被其他进程所访问。
不管对该租借锁减短租约或者干脆删除的操作是进程自愿的还是内核强迫的,只要被阻塞的系统调用还没有被发出该调用的进程解除阻塞,那么系统就会允许这个系统调用执行。

#define _GNU_SOURCE 
 
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/file.h>
{
        int res;
 
        res = fcntl(fd, F_GETLEASE);
        switch (res) {
                case F_RDLCK:
                        break;
                case F_WRLCK:
                        break;
                case F_UNLCK:
                        break;
                default:
                        break;
        }

{
        int fd, res;
 
        fd = open(argv[1], O_RDONLY);
        if (fd == -1) {
                return 1;
        }
 
        res = fcntl(fd, F_SETLEASE, F_WRLCK);
        if (res == -1) {
                return 1;
        }
 
        show_lease(fd);
 
        if (flock(fd, LOCK_SH) == -1) {
                return 1;
        }
 
        show_lease(fd);
 
        return 0;

gcc fcntl.c -o fcntl
 
su - test
Can't set lease: Permission denied
 
普通用户可以在自己的文件上(owner)建立租借锁.
 
setcap cap_lease=eip /tmp/fcntl
 
 
/tmp/fcntl /etc/passwd
Write lease
 
 
 

setcap CAP_SETFCAP=eip /usr/sbin/setcap 
 
setcap CAP_SETPCAP=eip /bin/ls
 
getcap /bin/ls                

 
CAP_AUDIT_WRITE
CAP_MAC_OVERRIDE
CAP_SYSLOG

 
 
CAP_CHOWN 0 允许改变文件的所有权 
CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制 
CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制 
CAP_FSETID 4 确保在文件被修改后不修改setuid/setgid位
CAP_KILL 5 允许对不属于自己的进程发送信号 
CAP_SETGID 6 允许改变组ID 
CAP_SETUID 7 允许改变用户ID 
CAP_LINUX_IMMUTABLE 9 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性 
CAP_NET_BIND_SERVICE 10 允许绑定到小于1024的端口 
CAP_NET_BROADCAST 11 允许网络广播和多播访问(未使用) 
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_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_SETFCAP 31 允许在指定的程序上授权能力给其它程序
 
man capabilities
linux-2.6.38.5/include/linux/capability.h
原文地址:https://www.cnblogs.com/sky-heaven/p/9481317.html