本实验中,我们将感受到linux capability功能在访问控制上的优势,掌握使用Capability达到遵守最小权限原则的目的,并分析linux中基于Capability访问控制的设计。
下载Libcap
$ cd $ wget http://labfile.oss.aliyuncs.com/libcap-2.21.tar.gz $ tar xvf libcap-2.21.tar.gz $ sudo rm /usr/include/sys/capability.h $ sudo rm /lib/libcap.so* $ cd /home/shiyanlou/libcap-2.21/ $ sudo make $ sudo make install
在操作系统中,有许多只允许超级用户使用的操作,比如配置网卡,备份所有用户文件,关闭计算机等,但如果要进行这些操作就必须先成为超级用户的话,那就违背了最小权限原则。
Set-UID程序允许用户暂时以root权限进行操作,即使程序中所进行的权限操作用不到root权限的所有权利,这很危险:因为如果程序被入侵了的话,攻击者可能得到root权限。
Capabilities将root权限分割成了权利更小的权限。小权限被称作capability。如果使用capabilities,那么攻击者最多只能得到小权限,无法得到root权限。这样,风险就被降低了。
1.用普通用户登录
$ ping -c 3 www.baidu.com
2.使用root权限运行第一步命令并执行如下命令
$ sudo su # setcap cap_net_raw=ep /bin/ping # exit $ ping -c 3 www.baidu.com
实验结果如下
$ sudo su seed $ sudo chmod u-s /usr/bin/passwd $ passwd $ sudo setcap cap_chown,cap_dac_override,cap_fowner=ep /usr/bin/passwd $ passwd
实验结果如下所示
这一步证明一开始无法修改密码,但是在分配了cap之后就可以成功修改密码:
seed 用户的密码是 dees。
3.调整权限
跟使用ACL的访问控制相比,capabilities有其它优势:它可以动态调整大量线程的权限,这对于遵守最小权限原则是很有必要的。当线程中某个权限不再需要时,它应当移除所有相对应的capabilities。这样,即使线程被入侵了,攻击者也得不到已经被删除的capabilities。使用以下管理操作调整权限:
Deleting:线程永久删除某个capability
Disabling:线程会暂时停用某个capability。
Enabling:对应Disabling,启用capability。
为了支持动态的capability分配,Linux使用一个与Set-UID相近的机制。举个例子,一个线程具有3组capability设置:允许(permitted P),可继承(inheritable I),和有效(effective E)。允许组由允许线程使用的cap组成,但其中的cap可能还没有激活。有效组由线程当前可以使用的cap组成。有效组是允许组的子集。线程可以随时更改有效组的内容只要不越过允许组的范围。可继承组是在程序运行exec()调用后计算新子线程的cap组用的。
当一个线程fork新线程的时候,子线程的cap组从父线程拷贝。当在一个线程中运行一个新程序时,它的新cap组将根据以下公式计算:
pI_new = pI pP_new = fP | (fI & pI) pE_new = pP_new if fE = true pE_new = empty if fE = false
new后缀指新计算值,p前缀指线程,f前缀指文件cap。I,P,E分别指代 inheritable,permitted,effective,是一个cap位一个cap位计算的。
切换到 /home/shiyanlou/libcap-2.21/libcap 目录下,编辑 cap_proc.c文件。为了让程序操作cap变得简单,添加以下三个函数到 /home/shiyanlou/libcap-2.21/libcap/cap_proc.c 中。
/* Disable a cap on current process */ int cap_disable(cap_value_t capflag) { cap_t mycaps; mycaps = cap_get_proc(); if (mycaps == NULL) return -1; if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_CLEAR) != 0) return -1; if (cap_set_proc(mycaps) != 0) return -1; return 0; } /* Enalbe a cap on current process */ int cap_enable(cap_value_t capflag) { cap_t mycaps; mycaps = cap_get_proc(); if (mycaps == NULL) return -1; if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) != 0) return -1; if (cap_set_proc(mycaps) != 0) return -1; return 0; } /* Drop a cap on current process */ int cap_drop(cap_value_t capflag) { cap_t mycaps; mycaps = cap_get_proc(); if (mycaps == NULL) return -1; if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_CLEAR) != 0) return -1; if (cap_set_flag(mycaps, CAP_PERMITTED, 1, &capflag, CAP_CLEAR) != 0) return -1; if (cap_set_proc(mycaps) != 0) return -1; return 0; }
之后编译安装。
在 /home/shiyanlou/libcap-2.21/libcap 目录下新建一个 use_cap.c 文件,并分配cap_dac_read_search给它。
#include <fcntl.h> #include <sys/types.h> #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <linux/capability.h> #include <sys/capability.h> int main( void ) { if ( open( "/etc/shadow", O_RDONLY ) < 0 ) printf( "(a) Open failed\n" ); if ( cap_disable( CAP_DAC_READ_SEARCH ) < 0 ) return(-1); if ( open( "/etc/shadow", O_RDONLY ) < 0 ) printf( "(b) Open failed\n" ); if ( cap_enable( CAP_DAC_READ_SEARCH ) < 0 ) return(-1); if ( open( "/etc/shadow", O_RDONLY ) < 0 ) printf( "(c) Open failed\n" ); if ( cap_drop( CAP_DAC_READ_SEARCH ) < 0 ) return(-1); if ( open( "/etc/shadow", O_RDONLY ) < 0 ) printf( "(d) Open failed\n" ); if ( cap_enable( CAP_DAC_READ_SEARCH ) == 0 ) return(-1); if ( open( "/etc/shadow", O_RDONLY ) < 0 ) printf( "(e) Open failed\n" ); }
最后编译运行。实验结果如下所示
问题一、当我们想动态调整基于ACL访问控制权限的数量时,应该怎么做?与capabilities比较哪种更加便捷?
ACL访问控制即通过查询访问控制列表来获得访问主体权限的访问控制。当我们想动态调整基于ACL访问控制权限的数量时,我们通过修改访问控制列表中用户的访问权限来进行调整。ACL方式与capabilities相比,capabilities更便捷。Linux提供了直接修改进程权能的系统调用sys_capset(),进程可以通过sys_capset()调用来直接修改除init进程以外的任何进程的各权能集。而ACL需要调整访问控制列表中文件的安全域和权限等进行权限调整。
问题二、当程序(以普通用户运行)禁用cap A时,它遭到了缓冲区溢出攻击。攻击者成功注入恶意代码并运行。他可以使用cap A么?如果线程删除了cap A呢,可以使用cap A么?
当程序(以普通用户运行)禁用cap A时,它遭到了缓冲区溢出攻击。导致cap A没有成功禁用,攻击者成功注入恶意代码并运行,可以使用capA。如果线程删除了capA,则capA已经成功禁用,攻击者不可以使用capA。
问题三、问题如上,改用竞态条件攻击。他可以使用cap A么?如果线程删除了cap A呢,可以使用cap A么?
改用竟态条件攻击,程序禁用cap A,竟态攻击者抢占资源,可以获得capA使用权限。如果线程删除了capA,竟态攻击者依然可以抢占资源,取得capA的使用权限。