转自: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
普通用户要用/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 \n", (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