Set-UID程序漏洞

目录

一、实验目的

二、实验要求

三、实验环境

四、实验过程

1、Set-UID程序的作用

2. 运行Set-UID Shell程序

3、更改默认Shell

4、PATH环境变量的影响

5、system()与execve()的区别

6、LD_PRELOAD环境变量

7、权限释放与清理


一、实验目的

  本实验的主要目的是通过探索Linux系统中的Set-UID机制,理解其工作原理及其潜在的安全问题。Set-UID是Unix和Linux操作系统中一种重要的安全机制,允许程序在运行时获取其所有者的权限。通过本实验,能够:

  1.理解Set-UID机制的必要性:了解为什么某些命令(如passwd、chsh、su、sudo等)需要设置为Set-UID程序,以及它们在系统中的重要作用。

  2.认识Set-UID机制的安全隐患:通过实际操作,发现Set-UID机制可能带来的安全问题,理解如何通过环境变量、系统调用等方式滥用Set-UID程序,从而提升对系统安全的意识。

二、实验要求

实验分为多个任务,通过以下步骤逐步探索Set-UID机制的工作原理及其潜在的安全隐患:

1Set-UID程序的作用

分析常见的Set-UID程序(如passwd、chsh、su、sudo),理解它们为什么需要Set-UID权限,并观察当这些程序失去Set-UID权限时的行为变化。

2运行Set-UID Shell程序

以root用户身份复制/bin/zsh和/bin/bash到/tmp目录,并将它们设置为Set-UID程序。然后以普通用户身份运行这些程序,观察是否能够获得root权限,并解释结果。

3更改默认Shell

把/bin/sh链接到/bin/zsh,以便在后续任务中使用zsh作为默认Shell,绕过bash对Set-UID的保护机制。

4PATH环境变量的影响

通过修改PATH环境变量,尝试让一个Set-UID程序执行自定义代码,而不是原本的/bin/ls命令,观察是否能够以root权限运行自定义代码。

5system()与execve()的区别

分析一个使用system()调用的Set-UID程序的安全性,尝试通过特殊字符攻击系统。然后将程序改为使用execve()调用,观察攻击是否仍然有效。

6LD_PRELOAD环境变量

创建一个动态链接库,覆盖libc中的sleep()函数,并设置LD_PRELOAD环境变量。通过在不同条件下运行程序,观察LD_PRELOAD环境变量是否被忽略,并解释原因。

7权限释放与清理

编写一个Set-UID程序,尝试在完成任务后释放root权限,观察在子进程被攻击的情况下,系统文件/etc/zzz是否会被修改,并解释原因。

三、实验环境

开发环境

Visual Studio

运行环境

Linux(ubuntu)

测试环境

终端(笔记本)

四、实验过程

1、Set-UID程序的作用

Set-UID(Set User ID)是Linux/Unix系统中的一种权限机制。当一个程序被设置为Set-UID时,无论谁运行这个程序,它都会以程序文件的所有者(通常是root)的权限运行。例如,如果passwd是一个Set-UID程序,且其所有者是root,那么无论普通用户还是root用户运行passwd,它都会以root权限执行。

首先在使用Set-UID权限的情况下运行指令

(1)passwd

(2)chsh

    

    (3)su

    (4) sudo

    这些命令需要修改系统中的敏感文件或执行特权操作,而这些操作通常只有root用户才有权限执行。例如:

    passwd:需要修改/etc/shadow文件(存储用户密码的文件),普通用户没有权限直接修改该文件。

    chsh:需要修改/etc/passwd文件(存储用户登录Shell的文件)。

    su:允许用户切换到其他用户(如root),需要访问/etc/shadow文件验证密码。

    sudo:允许普通用户以root权限执行命令,需要验证用户权限并提升权限。

    如果这些命令没有Set-UID权限,普通用户将无法执行这些特权操作,导致系统功能受限。

    接下来移除Set-UID权限,使用如下命令:

    cp /usr/bin/passwd ~/mypasswd

    cp /usr/bin/chsh ~/mychsh

    cp /usr/bin/su ~/mysu

    cp /usr/bin/sudo ~/mysudo

    示例如下:

    可见,文件权限中没有s标志,说明它不是Set-UID程序

    再次运行这些命令

    passwd

    chsh

    su

    sudo

    显示未设置set-uid位

    由此可见,以上这些命令失去了set-uid权限后,均不能成功运行。

    2. 运行Set-UID Shell程序

    通过运行Set-UID的Shell程序(如zsh和bash),观察是否能够获得root权限,并解释zsh和bash的行为差异。

    (1)实验过程

    首先安装好zsh

    将/bin/zsh复制到/tmp目录

    使用chmod命令为/tmp/zsh设置Set-UID权限

    切换回普通用户,运行/tmp/zsh,使用id查看当前用户

    输出显示uid=0(root),说明获得了root权限

    使用类似的步骤测试bash

    输出显示uid=1000(lois),说明没有获得root权限

    解释zsh和bash的行为差异

    (1)zsh的行为

    zsh在设置为Set-UID程序后,会直接以root权限运行,普通用户可以通过运行/tmp/zsh获得root权限。这种行为存在安全风险,因为攻击者可以利用Set-UID的zsh程序提升权限。

    (2)bash的行为

    bash在设置为Set-UID程序后,会检测到自己是Set-UID程序,并自动降低权限,以普通用户身份运行。这是bash的一种安全保护机制,防止Set-UID程序被滥用。

    (3)zsh和bash行为不同

    bash在设计时加入了额外的安全检查,当它发现自己是以Set-UID程序运行时,会主动放弃root权限,以普通用户身份运行。zsh没有类似的安全机制,因此会直接以root权限运行。

    zsh在设置为Set-UID程序后,普通用户可以通过运行它获得root权限。

    bash在设置为Set-UID程序后,会自动降低权限,防止普通用户获得root权限。

    这种行为差异是由于bash和zsh在安全性设计上的不同。bash通过额外的安全检查,避免了Set-UID机制的滥用。

    3、更改默认Shell

    在之前的任务中,我们发现/bin/bash具有内置的保护机制,防止Set-UID机制被滥用。为了模拟在没有这种保护机制的情况下系统的行为,我们需要将默认Shell从bash更改为zsh。具体来说,我们需要将/bin/sh(默认Shell)从指向/bin/bash改为指向/bin/zsh。

    首先将/bin/sh从指向/bin/bash改为指向/bin/zsh

    测试过程中却出现了问题

    手动更新环境变量

    4、PATH环境变量的影响

    通过修改PATH环境变量,尝试让一个Set-UID程序执行用户自定义的代码,而不是原本的/bin/ls命令。观察是否能够以root权限运行自定义代码,并分析system()函数的安全性问题。

    1运行/bin/ls

    编写myls.c程序。

    将程序设置为Set-UID程序

    创建恶意程序

    编译,然后修改PATH环境变量,使其优先搜索当前目录,运行./myls,输出Hacked,说明恶意程序成功执行。

    (2)指向/bin/bash

    若要防范,可采用bash,过程如下:

    以root用户登录,将/bin/sh重新链接到/bin/bash

    再次运行Set-UID程序

    可见输出正常。

    (3)安全性分析

    system()函数通过调用/bin/sh来执行命令,而/bin/sh的行为受环境变量(如PATH)的影响。

    由于PATH环境变量可以被用户控制,攻击者可以通过修改PATH,让system()执行恶意程序,而不是原本的命令。

    由于Set-UID程序以root权限运行,恶意程序也会以root权限运行,从而导致权限提升。

    若要防范,在Set-UID程序中,避免使用system()函数,改用更安全的函数(如execve())。

    如果必须使用system(),应使用绝对路径来指定命令。

    system("/bin/ls");

    使用zsh时:攻击成功,恶意程序以root权限运行。这是因为zsh没有对Set-UID机制进行额外的安全检查。

    使用bash时,攻击失败,恶意程序无法以root权限运行。这是因为bash在检测到自己是Set-UID程序后,会自动放弃root权限。

    因此,在编写Set-UID程序时,避免使用system()函数,改用更安全的函数(如execve()),如果必须使用system(),应使用绝对路径来指定命令,避免受环境变量的影响。

    5、system()与execve()的区别

    通过分析一个Set-UID程序,比较system()和execve()函数的安全性。具体来说,观察在使用system()时是否可以通过特殊字符攻击系统,以及在使用execve()时是否能够防范此类攻击。

    以root用户登录,将/bin/sh链接到/bin/zsh

    编写Set-Uid程序

    编译并设置为Set-UID程序

    (1)q = 0,使用system

    运行程序,可以显示出/etc/passwd文件的内容

    运行程序时使用特殊字符注入命令,发现攻击成功,/tmp/testfile文件被删除

    2q = 1,使用execve

    testfile文件删除失败(这里不知道为什么显示的是未找到,但确实是删除失败了)

      使用system()时,攻击成功,恶意命令以root权限运行。这是因为system()函数通过调用/bin/sh来执行命令,而/bin/sh会解析特殊字符,导致命令注入攻击。

      使用execve()时,攻击失败,恶意命令无法执行。这是因为execve()函数直接执行指定的程序,而不会调用Shell来解析命令,从而防范了命令注入攻击。

    6、LD_PRELOAD环境变量

    观察LD_PRELOAD环境变量对Set-UID程序的影响,分析运行时链接器(ld.so)在什么情况下会忽略LD_PRELOAD环境变量,并解释原因。

    (1) 准备工作

    编写一个程序用于覆盖libc中的sleep()函数。

    编译该程序为动态链接库

    设置LD_PRLOAD环境变量,指向刚刚编译的动态链接库

    编写如下程序

      (2) 以普通身份运行

    输出为“I am not sleeping”,说明LD_PRELOAD环境变量生效,动态链接库中的sleep()函数被调用。

    (3) 作为Set-UID root 程序运行

    将myprog设置为Set-UID root程序,以普通用户身份运行myprog,输出为空,说明LD_PRELOAD环境变量被忽略

    (4) 作为Set-UID root程序在root账户下运行

      LD_PRELOAD 被忽略,程序不会加载 LD_PRELOAD 指定的库。

    尽管 root 用户本身具有非常高的权限,但在执行 Set-UID 程序时,为了安全考虑,ld.so 会采取更加严格的措施,不允许通过环境变量影响程序的行为。否则,恶意程序或攻击者可以通过 LD_PRELOAD 加载特定的库并利用漏洞进行攻击,绕过安全机制。

    (5) 作为Set-UID user1程序运行

    更改 myprog 的所有者:首先将 myprog 的文件所有者更改为 user1。将Set-UID 位设置在 myprog 上,使得程序在运行时以 user1 的身份执行。 

    运行 myprog 程序。发现没有输出

    Set-UID 程序设计时,尤其是涉及高权限(如 root 或用户特权)时,为了防止恶意库的注入,运行时链接器(ld.so)会禁用 LD_PRELOAD 环境变量。这是为了防止用户通过修改 LD_PRELOAD 来加载恶意库,从而控制程序行为或提升权限。不管是 root 用户,还是其他用户执行 Set-UID 程序,LD_PRELOAD 环境变量都将被忽略,以防止恶意用户通过动态链接库注入恶意代码。

    7、权限释放与清理

      编译如下代码

      以 root 权限运行,将它设置为 setuid 程序。使用 chmod 命令将程序的 setuid 位设置为 root。

    创建 /etc/zzz 文件,使用 touch 命令创建该文件,并将其权限设置为 0644

     切换至普通用户运行。

    查看/etc/zzz 文件内容,发现输出“Malicious Date”,可知文件修改成功。

    setuid() 系统调用用于修改当前进程的用户 ID。调用 setuid(getuid()) 后,进程的有效用户 ID (effective UID) 被设置为当前用户的真实用户 ID (real UID),使进程失去 root 权限。这通常用于放弃不必要的特权,提高系统安全性,防止滥用 root 权限。

    然而,setuid() 仅影响进程的用户 ID 和组 ID,并不会影响该进程在执行期间已经打开的文件描述符的权限。文件描述符依然保持原始的访问权限,直到关闭。

    在程序中,文件 /etc/zzz 被打开并赋予文件描述符 fd。程序调用 setuid(getuid()) 之后,虽然进程的 UID 被修改,放弃了 root 权限,但文件描述符 fd 依然持有对 /etc/zzz 文件的读写权限。这是因为文件描述符的权限和进程的 UID 是分开管理的。

    在 fork() 之后,子进程继承了父进程的文件描述符,因此,子进程依然拥有对该文件的访问权限,即使它的 UID 已经不再是 root。

    子进程在继承父进程的文件描述符后,会继续保有文件描述符所指向文件的访问权限。因此,尽管父进程通过 setuid() 放弃了 root 权限,但子进程依然能够通过这些文件描述符执行修改操作,即写入数据到 /etc/zzz 文件。

    该漏洞的表现是,程序通过 fork() 创建子进程,子进程会继续执行并成功写入 "Malicious Data" 到 /etc/zzz 文件。攻击者可以利用这一点,通过控制子进程的行为,执行恶意代码,即使父进程已经放弃 root 权限。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

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

      抵扣说明:

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

      余额充值