(2023-2024-1)20232830《Linux内核原理分析与设计》第十三周作业

(2023-2024-1)20232830《Linux内核原理分析与设计》第十三周作业

1. Linux Capability探索实验

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

2. 环境搭建

下载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

相关命令:

  • setcap: 给一个文件分配capabilities;
  • getcap: 显示文件所带的capabilities;
  • getpcaps: 显示线程所在的capabilities;

1
以上,就完成了实验环境的搭建。

3. 实验内容

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

3.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

接下来,关闭程序的suid位:

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

2
继续尝试ping百度;
1
提示操作不被允许。这是因为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

2
使用ping命令之后,发现能够发送包,但接收失败,应该是本地网络问题,但没有出现提示操作不被允许。

接着修改seed用户的密码,密码为dees;命令如下:

$ 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
成功修改密码,密码为:shiyanlou。

3.2 调整权限

切换到 /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;
}

在将函数添加之后,运行以下命令编译安装libcap:

$ sudo make
$ sudo make install    

2
编译安装完成,接下来在 /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

2
从运行结果可知,打开失败,即不具备权限。

3.3 课后问题

问题1:当我们想动态调整基于ACL访问控制权限的数量时,应该怎么做?与capabilities比较哪种更加便捷?
回答:当我们想要动态调整基于ACL(访问控制列表)的权限数量时,可以采取以下步骤:

  1. 审查和修改ACL:首先,需要审查当前的ACL设置,了解其中包含的权限和相应的实体(用户、组织等)。然后,根据需要调整权限数量,可以添加、删除或修改ACL中的权限条目。
  2. 考虑访问需求:在进行权限调整之前,需要仔细考虑实际的访问需求。确定哪些权限是必要的,哪些是多余的,以及是否需要添加新的权限来满足特定的访问要求。
  3. 定义权限策略:根据访问需求,制定适当的权限策略。这可能涉及到分配不同级别的权限给不同的用户或组织,或者根据角色和责任来定义权限。
  4. 实施权限调整:根据定义的权限策略,对ACL进行相应的调整。这可能需要在操作系统、应用程序或网络设备中进行配置更改,以确保权限的动态调整生效。

与ACL相比,capabilities(能力)模型在动态调整权限数量方面更加便捷。在capabilities模型中,权限是与资源直接关联的,每个资源都有其自己的能力列表。当需要调整权限时,可以直接修改资源的能力列表,添加或删除特定的能力。这种能力模型可以更灵活地控制和管理权限,而无需修改全局的访问控制策略。

问题2:当程序(以普通用户运行)禁用cap A时,它遭到了缓冲区溢出攻击。攻击者成功注入恶意代码并运行。他可以使用cap A么? 如果线程删除了cap A呢,可以使用cap A么?
回答:在Linux系统中,capabilities(能力)是一种细粒度的权限控制机制,用于限制进程在特权模式下的权限。当程序禁用了cap A,即取消了拥有cap A的能力时,普通用户运行的程序将失去cap A的能力。

在发生缓冲区溢出攻击并成功注入恶意代码后,攻击者运行的恶意代码将在普通用户权限下执行。无论攻击者是否删除了cap A,他都无法使用cap A,因为已经在程序中明确禁用了cap A。

删除cap A是一个特权操作,普通用户线程无法直接删除自身的能力。只有具有足够特权的进程(例如root用户)才能删除或修改线程的能力。因此,即使线程删除了cap A,普通用户线程仍然无法使用cap A。

需要注意的是,缓冲区溢出攻击和恶意代码注入是一种严重的安全漏洞,攻击者可以通过利用这些漏洞来执行恶意操作。为了防止此类攻击,应采取安全编码实践,如输入验证和缓冲区溢出保护,以确保程序的安全性。同时,最小化权限并遵循最小权限原则,可以减轻潜在攻击的影响范围。

问题3:问题如上,改用竞态条件攻击。他可以使用cap A么? 如果线程删除了cap A呢,可以使用cap A么?
回答:竞态条件攻击是一种利用并发环境中的竞争条件来实施攻击的方法。在这种攻击中,攻击者试图在受攻击程序中创建或修改资源的竞争条件,以获取超出其权限的访问权限。

无论是普通用户程序还是恶意注入的代码,都无法直接使用已禁用的cap A能力。即使线程删除了cap A,普通用户线程也无法使用cap A。

在Linux系统中,capabilities的授权是静态的,无法通过竞态条件攻击来获取被禁用的能力。删除或修改能力需要特权权限,普通用户线程无法直接进行这样的操作。

竞态条件攻击是一种利用并发环境中的竞争条件来实施攻击的方法。攻击者试图通过在关键操作之间插入恶意代码,利用并发执行的不确定性,以获得超出其权限的访问或执行权限。

在竞态条件攻击中,如果攻击者成功利用并发竞争条件,可能会导致程序以未预期的方式执行,包括获取一些特权操作的能力。如果攻击者成功利用竞态条件来获取特权操作的能力,那么他可能会使用cap A或其他特权操作。

然而,如果线程已删除了cap A,那么无论是否发生竞态条件攻击,普通用户线程都无法使用cap A。删除cap A是一个特权操作,普通用户线程无法直接进行这样的操作。

需要注意的是,竞态条件攻击是一种复杂的攻击技术,其成功取决于多个因素,包括并发环境、操作系统和应用程序的实现等。为了防止竞态条件攻击,应采取适当的安全措施,如加强并发环境的同步机制、使用事务操作或采用其他安全编码实践来确保程序的安全性。

4. 总结

Linux Capability 是一种在 Linux 操作系统中实现权限控制的机制,它具有以下优势:

  1. 细粒度控制:Capability 允许对进程或线程进行细粒度的权限控制。每个 Capability 代表一个特定的操作或权限,可以单独分配给进程或线程,从而实现更精确的权限管理。

  2. 最小权限原则:使用 Capability 可以帮助实现最小权限原则,即将最低必要的权限分配给进程或线程,以最大程度地减少潜在的安全风险。通过将权限限制在需要的最小范围内,可以减少攻击者利用特权执行的可能性。

  3. 动态管理:Capability 允许在运行时动态管理权限。进程或线程可以在需要时获取或释放权限,而无需重新启动整个系统或应用程序。这种动态管理的能力使得权限调整更加便捷和灵活。

在基于 Capability 的访问控制设计中,可以采用以下策略:

  1. 分割权限:将不同的操作或权限划分为独立的 Capability。通过细分权限,可以更好地控制和管理不同级别的访问需求。例如,可以将网络操作、文件系统操作和进程管理等权限分配给不同的 Capability。

  2. 角色和责任:基于角色和责任来定义 Capability 的分配。根据用户或进程的角色和责任,分配相应的 Capability。这样可以确保每个角色只具有其所需的权限,遵循最小权限原则。

  3. 权限继承:在某些情况下,可以通过权限继承来简化权限管理。例如,可以为进程组分配相同的 Capability,以便组内的所有进程都具有相同的权限。这样可以简化管理并确保一致的访问控制。

  4. 审计和监控:在基于 Capability 的访问控制设计中,应该实施审计和监控机制来跟踪权限的使用情况。这样可以及时检测异常行为并采取必要的措施。

总而言之,Linux Capability 提供了细粒度的权限控制和动态管理的能力,使得基于 Capability 的访问控制设计能够更好地遵守最小权限原则。通过合理划分权限、角色和责任的分配、权限继承以及审计和监控,可以实现更可靠和安全的访问控制机制。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值