2023-2024-1 20232824《Linux内核原理与分析》第十三周作业

Linux Capability 探索实验

本实验中,将感受到linux capability功能在访问控制上的优势,掌握使用Capability达到遵守最小权限原则的目的,并分析linux中基于Capability访问控制的设计。

一、环境搭建

在进行实验之前,首先需要做一些准备工作。

下载Libcap

libcap 库能够使用户级别的程序与 capability 特性做交互,一些linux发行版不包括这个库,在环境中已经有 /usr/include/sys/capability.h 这个文件,为了避免老版本的影响,我们还是删掉以前的,然后重新下载一个。

$ 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

在一个capability系统中,当一个程序运行时,对应的线程会初始化一系列capabilities(令牌)。当线程尝试访问某个对象时,操作系统会检查该线程的capabilities,并决定是否授权访问。

二、实验内容

在一个capability系统中,当一个程序运行时,对应的线程会初始化一系列capabilities(令牌)。当线程尝试访问某个对象时,操作系统会检查该线程的capabilities,并决定是否授权访问。

1.感受Capabilities

在操作系统中,有许多只允许超级用户使用的操作,比如配置网卡,备份所有用户文件,关闭计算机等,但如果要进行这些操作就必须先成为超级用户的话,那就违背了最小权限原则。

Set-UID程序允许用户暂时以root权限进行操作,即使程序中所进行的权限操作用不到root权限的所有权利,这很危险:因为如果程序被入侵了的话,攻击者可能得到root权限。

Capabilities将root权限分割成了权利更小的权限。小权限被称作capability。如果使用capabilities,那么攻击者最多只能得到小权限,无法得到root权限。这样,风险就被降低了。

在kernel版本2.6.24之后,Capabilities可以分配给文件(比如程序文件),线程会自带程序文件被分配到的capabilities。

下面这个例子演示capabilities如何移除root特权程序中的不必要的权利。

首先,以普通用户登录并运行以下命令:

$ ping -c 3 www.baidu.com

命令成功运行,如果你查看/bin/ping的属性会发现它是一个root所有的Set-UID程序。如果ping中包含漏洞,那么整个系统就可能被入侵。问题是我们是否能移除ping的这些权限。

让我们关闭程序的suid位:

$ sudo su
# chmod u-s /bin/ping

# exit
$ ping www.baidu.com
ping: icmp open socket: Operation not permitted

然后再ping百度,它会提示你操作不被允许。这是因为ping命令需要打开RAW套接字,该操作需要root特权,这就是为什么ping是Set-UID程序了。但有了capability,我们就可以杯酒释兵权了,让我们分配cap_net_raw给ping,看看会发生什么:

$ sudo su
# setcap cap_net_raw=ep /bin/ping
# exit
$ ping -c 3 www.baidu.com

1.取消下列程序的Set-UID并不影响它的行为。

这一步证明一开始无法修改密码,但是在分配了cap之后就可以成功修改密码:

$ 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

2.熟悉一下其它capability
  1. cap_dac_read_search(读取搜索):

    • 描述: 此能力允许进程绕过文件系统的文件读取和目录搜索权限检查。
    • 用例: 常用于需要访问文件和目录而不受传统文件权限限制的进程。
  2. cap_dac_override(覆盖访问控制):

    • 描述: 此能力允许进程覆盖文件的自主访问控制(DAC)。
    • 用例: 具有此能力的进程可以访问和修改文件,即使它们没有必要的文件权限。
  3. cap_chown(更改所有者):

    • 描述: 此能力允许进程更改文件的所有者。
    • 用例: 用于需要更改文件所有者的进程,通常是管理任务。
  4. cap_setuid(设置用户ID):

    • 描述: 此能力允许进程将其有效用户ID更改为任何其他用户ID。
    • 用例: 常用于需要临时提升权限以执行某些操作的特权进程或程序。
  5. cap_kill(杀死进程):

    • 描述: 此能力允许进程向任意进程发送信号。
    • 用例: 用于需要管理其他进程的进程,如进程管理器或系统级实用程序。
  6. cap_net_raw(原始网络访问):

    • 描述: 此能力允许进程使用原始套接字。
    • 用例: 常用于需要在网络层发送和接收数据包的网络相关实用程序或服务。

这些能力提供了比传统Unix文件权限更细粒度的控制,允许进程执行特定的特权操作而无需授予完整的root(超级用户)访问权限。需要注意的是,通常与其他安全机制一起使用这些能力,以确保适当的访问控制。

2.调整权限

跟使用ACL的访问控制相比,capabilities有其它优势:它可以动态调整大量线程的权限,这对于遵守最小权限原则是很有必要的。当线程中某个权限不再需要时,它应当移除所有相对应的capabilities。这样,即使线程被入侵了,攻击者也得不到已经被删除的capabilities。使用以下管理操作调整权限:

  1. Deleting:线程永久删除某个capability
  2. Disabling:线程会暂时停用某个capability。
  3. 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文件。

$ exit
$ cd /home/shiyanlou/libcap-2.21/libcap
$ sudo vi 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;
}

运行以下命令编译安装libcap:

$ sudo make
$ sudo make install    

1. 在 /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" );

}

使用以下命令编译运行:

$ gcc -c use_cap.c
$ gcc -o use_cap use_cap.o -lcap
$ ./use_cap

当我们想动态调整基于ACL访问控制权限的数量时,应该怎么做?与capabilities比较哪种更加便捷?

动态调整基于ACL(访问控制列表)的访问控制权限数量的方法取决于具体的需求和操作系统。ACLs允许对单个文件或目录应用更细粒度的权限,而不仅仅是传统的基于所有者、组和其他用户的权限。以下是一些常见的方法:

动态调整ACL权限的方法:

  1. 使用setfacl命令(Linux/Unix):

    • setfacl命令可以用于设置ACL权限。通过添加、修改或删除ACL规则,您可以在不更改文件所有者或组的情况下调整权限。

    • 例如,添加ACL规则:setfacl -m u:username:rw- filename

  2. 通过文件管理器(图形界面):

    • 有些桌面环境提供图形用户界面(GUI)工具,允许用户通过文件管理器直观地设置ACL权限。

与Capabilities比较:

  1. ACLs的优势:

    • 细粒度控制: ACLs允许对单个用户或用户组应用特定权限,提供了更细粒度的控制。

    • 灵活性: 您可以根据需要为不同的用户或组设置不同的权限。

  2. Capabilities的优势:

    • 轻量级: 能力通常更轻量级,更简单,因为它们是直接附加到进程而不是文件或目录。

    • 简化管理: 如果权限与进程的功能紧密相关,使用capabilities可能更方便,因为它避免了在文件层面管理权限的复杂性。

  3. 便捷性取决于具体场景:

    • 如果您需要对文件或目录的特定用户或组应用细粒度的控制,使用ACL可能更适合。

    • 如果权限与进程相关,并且您想要在运行时动态调整它们,capabilities可能更为方便。

选择使用ACL还是Capabilities取决于您的具体需求。在某些情况下,二者可能结合使用,以提供更全面的访问控制。

当程序(以普通用户运行)禁用cap A时,它遭到了缓冲区溢出攻击。攻击者成功注入恶意代码并运行。他可以使用cap A么? 如果线程删除了cap A呢,可以使用cap A么?

在Linux系统中,capabilities(能力)是进程级别的权限,用于控制进程可以执行的特权操作。当程序以普通用户身份运行时禁用了某个capability,通常情况下,即使发生缓冲区溢出攻击并成功注入恶意代码,攻击者也不会直接获得受限capability。

禁用capability后的情况:

  1. Capability已被禁用:

    • 如果程序运行时已经明确禁用了某个capability(例如,cap A),即使攻击者成功进行了缓冲区溢出攻击,注入了恶意代码,该恶意代码也无法利用被禁用的capability。这意味着即使攻击者能够运行恶意代码,也无法获得已被禁用的特权。

  2. 能否通过注入代码重新获取capability:

    • 在典型情况下,通过普通的缓冲区溢出攻击注入的代码,即使能够在进程空间内运行,也不能直接重新获取被禁用的capability。Capabilities设计为更加安全,即使发生漏洞攻击,也不容易被利用来获取额外的特权。

线程删除了capability的情况:

如果攻击者能够通过某种方式删除了程序本身拥有的capability,比如在注入的恶意代码中执行了对自身权限的修改,那么攻击者可能会利用这个机会获得额外的特权。

总结:

  • 通常情况下,被禁用的capability不太可能在缓冲区溢出攻击后被直接获取和利用。

  • 但是,如果攻击者能够在注入的恶意代码中执行权限的修改,删除了程序原本拥有的capability,那么可能会有一些风险。

在安全环境中,限制程序的权限并禁用不必要的capabilities是良好的实践,但即使发生漏洞,capabilities的设计也旨在减少被利用的可能性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值