zoukankan      html  css  js  c++  java
  • SEED实验——Environment Variable and Set-UID Program实验描述与实验任务

    第一部分:实验描述

    该实验的学习任务是理解环境变量是如何影响程序和系统行为的。环境变量是一组动态命名的变量


    第二部分:实验任务

    2.1 任务一:操作环境变量

    在这个任务中,我们研究可以用来设置和取消设置环境变量的命令。我们在seed实验环境中使用Bash。用户使用的默认shell在/etc/passwd文件(每个条目的最后一个字段)中设置。您可以使用命令chsh 将其更改为另一个shell程序(请不要在该实验中实现)。执行以下任务:

    • 使用printenv或env命令打印出环境变量。也可以单独打印出某个感兴趣的环境变量的值。例如:PWD,可以用如下命令:”printenv PWD “或者“env | grep PWD”单独打印出来。
    • 使用export或者unset命令设置或去掉环境变量。需要注意的是,这两个命令是Bash内部分命令。

    2.2  任务二:继承环境变量

    在这个任务中,我们学习环境变量是如何通过子进程完成继承机制。在Unix操作系统中,fork()通过负值调用进程建立一个新的进程。新的进程称为子进程,与其父进程完全相同。但是,子进程没有继承父进程的某些特性。(man fork)。在该任务中,我们会了解原坏境变量是否被子进程继承。

    • 步骤一:编译并运行程序:
      #include <unistd.h>
      #include <stdio.h>
      #include <stdlib.h>
      
      extern char **environ;
      
      void printenv()
      {
        int i = 0;
        while (environ[i] != NULL) {
           printf("%s
      ", environ[i]);
           i++;
        }
      }
      
      void main()
      {
        pid_t childPid;
      
        switch(childPid = fork()) {
          case 0:  /* child process */
              printenv();
          exit(0);
          default:  /* parent process */
              //printenv();
          exit(0);
        }
      }
      运行的结果(保存在child文件中):
    • 步骤二:在代码的switch语句中,子进程的情形下,注释掉printenv语句;父进程保持不变。编译并运行程序,将结果保存在child2文件中。
    • 步骤三:比较child和child2文件,写出结论。

    2.3 任务三:环境变量和execve()

    在该任务中,我们研究当通过execve()执行新程序时环境变量如何受到影响。函数execve()调用系统调用来加载新的命令并执行它。该函数不会返回,也咩没有新的过程被创建。相反,调用进程的文本,数据,bss和堆栈被加载的程序覆盖。基本上,execve()函数在调用进程内运行新的程序。我们对环境变量会发生什么感兴趣;他们是否自动继承了新程序?

    • 步骤一:编译并运行以下程序。描述观察到的实验结果。该程序简单地调用了/usr/bin/env,该系统调用能够打印出当前进程的环境变量。
    • 步骤二:现在,改变execve()函数的参数,描述你观察到的结果。
    • 步骤三:请得出关于新程序如何获取其环境变量的结论。

    2.4 任务四:环境变量和system()

    在该任务中,我们研究当通过system()执行新程序时华环境变量如何受到影响。system()函数被用于执行命令,但是不像execve()那样直接执行一个命令。system()函数实际上执行的是如下命令:“/bin/sh -c command”,例如执行“/bin/sh”,即请求一个shell。

    如果你看system()函数的实现,你会看到它使用execl()执行/bin/sh;excel()调用execve(),传递给它的环境变量数组。因此,使用system(),调用进程的环境变量被传递被新的程序/bin/sh。请编译并运行以下程序来验证这一点。

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
      system("/usr/bin/env");
    
      return 0 ;
    }

    2.5 任务五:环境变量和Set-UID程序

    Set-UID是一种重要的安全机制。当一个Set-UID程序运行时,它会获得程序所有者的特权。例如,如果程序所有者是root用户,那么任何人运行该程序时,该程序都会获得root用户的特权。Set-UID允许我们做许多有趣的事情,但是当它运行时,会升级用户的权限,会带来很大的风险。尽管Set-UID程序的行为是由代码逻辑决定的,而不是用户,用户能够通过环境变量来影响行为。为了理解Set-UID程序是如何被影响的,让我们首先指出哪些环境变量是否由用户进程的Set-UID程序的进程继承。

    • 步骤一:在当前步骤中写一个能够输出所有环境变量的程序
    #include <stdio.h>
    #include <stdlib.h>
    
    extern char **environ;
    
    void main()
    {
      int i = 0;
      while (environ[i] != NULL) {
         printf("%s
    ", environ[i]);
         i++;
      }
    }
    • 步骤二:编译以上程序,将其权限改为roo权限,使其成为一个Set-UID程序。
    • 步骤三:使用一般用户登录终端,使用export命令设置如下环境变量:PATH LD_LIBRARY_PATH ANY_NAME

    这些环境变量被设置在终端进程中。运行该Set-UID程序。在终端输入程序的名字后,终端会建立一个子进程,并用该子进程去运行程序。请检查上一步骤中设置的环境变量是否在子进程的shell中。描述观察到的结果。

    2.6 任务六:PATH环境变量和Set-UID程序

    由于调用了shell程序,所以在set-UID程序中调用system()是非常危险的。这是因为shell程序的实际行为可能受到环境变量的影响,如PATH这些环境变量由恶意用户提供。

    通过改变这些变量,恶意用户可以控制Set-UID程序的行为。在Bash中,您可以通过以下方式更改PATH环境变量(此示例将目录/home/seed添加到PATH环境变量的开头):

    $ export PATH=/home/seed:$PATH

    以下Set-UID程序应该执行/bin/ls命令。但是,程序员只能使用ls命令的相对路径,而不是绝对路径:

     int main()
       {
           system("ls");
           return 0;
       }

    编译上述程序,并将其所有者改为root,将其设置为Set-UID程序。你可以让这个Set-UID程序运行你的代码而不是/bin/ls吗?描述和解释你的观察。

    任务七:LD_PRELOAD环境变量和Set-UID程序

    在这个任务中,我们研究Set-UID程序如何处理环境变量。一些影响动态链接器的环境变量,包括LD_PRELOAD、LD_LIBRARY_PATH和其他LD_*。一个动态装载器/链接器是操作系统的一部分,用于下载并链接可执行文件运行过程中需要的公共库。

    ld.so或者ld-linux.so是动态加载器/链接器。在那些影响他们行为的环境变量中,LD_LIBRARY_PATH和LD_PRELOAD是该实验涉及到的两个环境变量。在linux中,LD_LIBRARY_PATH是一个冒号分隔的目录集,首先需要在标准的目录集之间搜索库。LD_PRELOAD指定要在所有其他库之前加载的其他用户指定的共享库列表。在这个任务中,我们只研究LD_PRELOAD。

    • 步骤一:首先,我们通过一个正常的程序理解环境变量如何影响动态加载器/链接器的行为。请按照以下步骤执行:

      1.我们新建一个动态链接库。命名下面的代码为mulib.c,该程序基本上覆盖了libc中的sleep函数:

    #include <stdio.h>
      void sleep (int s)
      {
        /* If this is invoked by a privileged program, 
           you can do damages here!  */
        printf("I am not sleeping!
    ");
      }

      2.用下列命令编译mylib.c:

    % gcc -fPIC -g -c mylib.c
    % -shared -o libmylib.so.1.0.1 mylib.o -lc

      3.设置LD_PRELOAD环境变量:

    % export LD_PRELOAD=./libmylib.so.1.0.1

      4.编译myprog程序,在链接库libmylib.so.1.0.1的相同目录下:

     /* myprog.c */
      int main()
      {
        sleep(1);
        return 0;
      }
    • 步骤二:在以下情况中运行myprog程序,观察发生了什么。

        1.以普通用户的身份运行myprog程序。

        2.以普通用户运行拥有root权限的myprog程序。

        3使myprog成为一个Set-UID user1程序,在user2用户(非root用户)中再次设置PD_PRELOAD环境变量,运行myprog程序。

    • 步骤三:观察以上三次程序的执行结果,理解导致他们不同的原因。环境变量起了作用。设计实验证明主要因素,并解释第二步中行为的不同。

    任务八:使用system()和execve()调用外部程序

    虽然system()和execve()都可以用于运行新程序,但是如果在特权程序(如Set-UID程序)中使用,则system()非常危险。我们已经看到PATH环境变量是如何影响system()的行为,因为该变量会影响shell的工作原理。execve()没有问题,因为它没有调用shell。调用shell会导致非常危险的后果,而这与环境变量无关。来看下面这种情况:鲍勃为一家审计机构工作,他需要调查一家公司是否有涉嫌欺诈。为了调查目的,鲍勃需要能够读取该公司Unix系统中的所有文件;另一方面,为了保护系统的完整性,鲍勃不能修改任何文件。为了实现这一目标,系统超级用户文斯写了一个特殊的设置root-UID程序(见下文),然后给出了对鲍勃的可执行权限。该程序要求鲍勃在命令行中键入文件名,然后运行/bin/cat显示了指定的文件。由于程序在root权限下运行,它可以显示鲍勃指定的任何文件。然而,由于程序没有写操作的权限,所以文斯非常确定鲍勃不能使用这个特殊的程序来修改任何文件。

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
      char *v[3];
      char *command;
    
      if(argc < 2) {
        printf("Please type a file name.
    "); 
        return 1;
      }
    
      v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = NULL;
    
      command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
      sprintf(command, "%s %s", v[0], v[1]);
    
      // Use only one of the followings.
      system(command);
      // execve(v[0], v, NULL);
    
      return 0 ;
    }
    • 步骤一:编译上面的程序,赋予其root用户权限,并将其变为SET-UID程序。该程序将会使用system()来调用命令。如果你是鲍勃,你能否打破系统的完整性吗?例如,你可以删除不可写文件吗?
    • 步骤二:注释掉system(command)语句,并取消注释execve()语句;程序将使用execve()来调用命令。编译程序,并使其成为Set-UID程序。那么在步骤一中的攻击是否仍然有效?

    任务九:权能泄露

    遵循最低权限原则,如果不再需要这种特权,Set-UID程序通常会永久放弃其root权限。此外,有时程序需要将其控制权交给用户,在这种情况下,root权限必须被撤销。setuid()系统调用可以用来撤销权限。根据手册,setuid()设置调用进程的有效用户ID。如果调用程序的有效UID是root,真实的UID和保存的set-user-id也被设置“。因此,如果一个有有效UID的set-uid程序没有调用setuid(n),则该进程将成为正常进程,其所有的UID都设置为n。当撤销权限的时候,最常见的错误就是权能泄露。这个进程在获得一些特权的时候可能已经获得了一些特权。当特权降级时,如果程序没有清理这个功能,则它们仍然可以由非特权进程访问。换句话说,虽然进程的有效用户ID变为非特权,但是该进程仍具有特权,因为它具有特权能力。

    编译以下程序,将其所有者更改为root,并将其设置为Set-UID程序。以普通用户身份运行程序,并描述您所观察到的内容。文件/etc/zzz是否被修改?

    请解释你的观察过程。

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    
    void main()
    { int fd;
    
      /* Assume that /etc/zzz is an important system file,
       * and it is owned by root with permission 0644.
       * Before running this program, you should creat
       * the file /etc/zzz first. */
      fd = open("/etc/zzz", O_RDWR | O_APPEND);
      if (fd == -1) {
         printf("Cannot open /etc/zzz
    ");
         exit(0);
      }
    
      /* Simulate the tasks conducted by the program */
      sleep(1);
    
      /* After the task, the root privileges are no longer needed,
         it's time to relinquish the root privileges permanently. */
      setuid(getuid());  /* getuid() returns the real uid */
    
      if (fork()) { /* In the parent process */
        close (fd);
        exit(0);
      } else { /* in the child process */
        /* Now, assume that the child process is compromised, malicious
           attackers have injected the following statements
           into this process */
    
        write (fd, "Malicious Data
    ", 15);
        close (fd);
      }
    }

  • 相关阅读:
    微信小程序promise解决onload异步
    小程序中使用 Less (VScode)
    Vue中使用less
    小程序获取 图片宽高
    ssh 登录出现Are you sure you want to continue connecting (yes/no)?解决方法
    SQL SERVER 收缩日志
    SQL SERVER-日期时间
    oracle判断查询结果是否为空
    修改Tomcat默认JDK版本
    Microsoft SQL Server Management Studio ------- 附加数据库 对于 服务器“xxx&amp;amp;quot;失败(错误码5120)
  • 原文地址:https://www.cnblogs.com/xlwang1995/p/7156252.html
Copyright © 2011-2022 走看看