mykaneki

V1

2022/09/20阅读:69主题:凝夜紫

SEED-Labs

lab 1 Set-UID

Task 1: Manipulating Environment Variables

控制环境变量

  1. 查看环境变量

    1. printenv or env
  2. 导出和清除变量

    1. export命令显示当前导出成用户变量的shell变量
    2. unset命令用于删除已定义的shell变量(包括环境变量)和shell函数。unset命令不能够删除具有只读属性的shell变量和环境变量
  3. 实验截图

    1. image-20220831113813559
      image-20220831113813559
    2. image-20220831113847032image-20220831115711495

      [08/30/22]seed@VM:~$ declare var1=1 var2=2 var3=3
      [08/30/22]seed@VM:~$ echo $var1 $var2 $var3 $var4
      1 2 3
      [08/30/22]seed@VM:~$ unset var2
      [08/30/22]seed@VM:~$ echo $var1 $var2 $var3 $var4
      1 3
      [08/30/22]seed@VM:~$ export | grep var
      declare -x XDG_DATA_DIRS="/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop"
      declare -x var1="1"
      declare -x var3="3"
      [08/30/22]seed@VM:~$ env |grep var
      var1=1
      var3=3
      XDG_DATA_DIRS=/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop
      [08/30/22]seed@VM:~$ set -a var
      [08/30/22]seed@VM:~$ export var2=2
      [08/30/22]seed@VM:~$ env |grep var
      var1=1
      var2=2
      var3=3
      XDG_DATA_DIRS=/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop
      [08/30/22]seed@VM:~$ readonly var2
      [08/30/22]seed@VM:~$ unset var2
      bash: unset: var2: cannot unsetreadonly variable

Task 2: Passing Environment Variables from Parent Process to Child Process

将环境变量从父进程传递给子进程

  1. 运行文件

    image-20220831120457012
    image-20220831120457012
  2. 注释①,取消注释②,再重新运行文件

    image-20220831121146030
    image-20220831121146030
  3. 比较两个文件

    image-20220831122252137
    image-20220831122252137
  4. 结论

    输出结果相同,父子进程的环境变量相同,子进程会完全继承父进程的环境变量

Task 3: Environment Variables and execve()

研究当一个新程序通过 Execve ()执行时,环境变量是如何受到影响的,例如:它们是否会被新程序自动继承

  1. 请编译并运行程序myenv.c,并描述您的观察结果。这个程序只是执行一个名为/usr/bin/env 的程序,它打印出当前进程的环境变量

    [08/31/22]seed@VM:~/.../Labsetup$ gcc myenv.c
    [08/31/22]seed@VM:~/.../Labsetup$ a.out > env1.txt
    [08/31/22]seed@VM:~/.../Labsetup$ vim env1.txt

    结果:无输出

  2. 修改execve("/usr/bin/env", argv, NULL);execve("/usr/bin/env", argv, environ);

    image-20220831210758674
    image-20220831210758674
  3. 比较两次结果

    • 第一次无结果,第二次结果和env命令运行结果相同,如图
    image-20220831213607172
    image-20220831213607172
    • 查询execve()原型及其功能:
    int execve(const char *filename, char *const argv[], 
               char *const envp[])

    execve()执行程序由 filename决定。 filename必须是一个二进制的可执行文件,或者是一个脚本以#!格式开头的解释器参数参数。如果是后者,这个解释器必须是一个可执行的有效的路径名,但是不是脚本本身,它将调用解释器作为文件名。

    argv是要调用的程序执行的参数序列,也就是我们要调用的程序需要传入的参数

    envp 同样也是参数序列,一般来说他是一种键值对的形式 key=value. 作为我们是新程序的环境

    • 结论:第一次未传入新程序的环境,因此无结果;第二次传入动态环境,作为env命令的参数,打印出来。因此,一个新程序通过execve()运行时,环境不会自动继承,需要手动传入。

    • 补充:为什么前面说的是动态环境?与environ相似的是envp。

    environ是全局变量,若程序执行过程中环境变量发生变化,则上述execve会采用最新的环境变量。envp是main函数运行时导入,若在main函数执行过程中环境变量发生修改,envp并不会修改,则execve函数使用旧版的环境变量,需要putenv(),setenv()重新获取。

Task 4: Environment Variables and system()

在这个任务中,我们研究了当一个新程序通过 system ()函数执行时,环境变量是如何受到影响的。这个函数用于执行命令,但是不同于 Executive ()直接执行命令,system ()实际上执行“/bin/sh-c 命令”,也就是说,它执行/bin/sh,并请求 shell 执行命令。如果查看 system ()函数的实现,您将看到它使用 Execl ()来执行/bin/sh; Execl ()调用 Execve () ,并将环境变量数组传递给它。因此,使用 system ()将调用进程的环境变量传递给新程序/bin/sh。请编译并运行以下程序来验证这一点

image-20220901211249393
image-20220901211249393

Task 5: Environment Variable and Set-UID Programs

Set-UID 是 Unix 操作系统中一种重要的安全机制。当 Set-UID 程序运行时,它假定拥有者的特权。例如,如果程序的所有者是 root 用户,当任何人运行该程序时,程序在执行期间获得 root 用户的特权。Set-UID 允许我们做许多有趣的事情,但是由于它提高了用户的权限,所以风险很大。虽然 Set-UID 程序的行为是由程序逻辑决定的,而不是由用户决定的,但是用户确实可以通过环境变量影响程序的行为。为了理解 Set-UID 程序是如何受到影响的,让我们首先弄清楚环境变量是否由 Set-UID 程序的进程从用户的进程继承

  1. 第一步:创建程序task5.c,并运行,观察

    image-20220901212139683
    image-20220901212139683
  2. 第二步:编译程序,修改所有者并提权,运行观察

    image-20220901212714336
    image-20220901212714336
  3. 第三步:在非root用户下修改环境,再次运行程序,观察

    1. 普通变量修改后依旧可以显示

      image-20220901213451492
      image-20220901213451492
    2. 修改变量PATH和新增变量LD_LIBRARY_PATH的测试情况

      image-20220901214743866
      image-20220901214743866

      PATH修改结果显示,但是LD_LIBRARY_PATH没有显示(经测试,直接在shell查看该环境可以显示出来)。

    3. 结论:LD_LIBRARY_PATH主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径。动态链接器的保护机制,为了使 Set-UID 程序更加安全,不受LD_LIBRARY_PATH环境变量的影响。如果程序是个 Set-UID 程序 ,运行时的链接器或加载器(ld.so)会忽略该环境变量,在编译后设置了该程序的有效ID为root,而在普通用户shell中运行时,真实用户为seed,因此此处设置的环境变量被忽略,没有起作用。

Task 6: The PATH Environment Variable and Set-UID Programs

由于调用的是 shell 程序,因此在 Set-UID 程序中调用 system ()非常危险。这是因为 shell 程序的实际行为可能受到环境变量(如 PATH)的影响; 这些环境变量由可能是恶意的用户提供。通过更改这些变量,恶意用户可以控制 Set-UID 程序的行为。在 Bash 中,您可以按照以下方式更改 PATH 环境变量(本示例将目录/home/種添加到 PATH 环境变量的开头

  1. 修改PATH

    image-20220904160420189
    image-20220904160420189
  2. 尝试运行恶意代码

    [09/04/22]seed@VM:~/.../Labsetup$ touch task6.c
    [09/04/22]seed@VM:~/.../Labsetup$ vim task6.c 
    [09/04/22]seed@VM:~/.../Labsetup$ touch fake_ls.c
    [09/04/22]seed@VM:~/.../Labsetup$ vim fake_ls.c 
    [09/04/22]seed@VM:~/.../Labsetup$ gcc task6.c -o task6.out
    task6.c: In function ‘main’:
    task6.c:3:1: warning: implicit declaration of function ‘system’ [-Wimplicit-function-declaration]
        3 | system("ls");
          | ^~~~~~
    [09/04/22]seed@VM:~/.../Labsetup$ sudo chown root task6.out
    [09/04/22]seed@VM:~/.../Labsetup$ sudo chmod 4755 task6.out
    [09/04/22]seed@VM:~/.../Labsetup$ export PATH=/home/seed/SEEDLabs/lab1/Labsetup:$PATH
    [09/04/22]seed@VM:~/.../Labsetup$ sudo ln -sf /bin/zsh /bin/sh
    [09/04/22]seed@VM:~/.../Labsetup$ gcc fake_ls.c  -o ls
    [09/04/22]seed@VM:~/.../Labsetup$ ./task6.out
    fakels!!!

  3. 总结:设置PATH最高优先搜索路径,可以改变system("ls")的执行程序

Task 7: The LD PRELOAD Environment Variable and Set-UID Programs

在本课题中,我们研究 Set-UID 程序如何处理一些环境变量。几个环境变量(包括LD_PRELOADLD_LIBRARY_PATH和其他 LD_*)影响动态加载程序/链接程序的行为。动态加载器/链接器是操作系统(OS)的一部分,操作系统加载(从持久存储到 RAM)并链接运行时可执行文件所需的共享库。在 Linux 中,ld.sold-Linux.so。因此,动态加载程序/链接器也是如此(每个加载程序/链接器用于不同类型的二进制文件)。在影响其行为的环境变量中,LD_LIBRARY_PATHLD_PRELOAD是本实验所关注的两个变量。在 Linux 中,LD LIBRARY PATH 是一组用冒号分隔的目录,在这些目录中,应该首先搜索库,然后才是标准目录集。LD_PRELOAD 指定要在所有其他库之前加载的用户指定的附加共享库列表。在这个任务中,我们将只研究LD_PRELOAD

  1. 环境变量在运行普通程序时如何影响动态加载程序/链接程序的行为

    1. 创建动态链接库,覆盖libc的sleep()

      /*mylib.c*/
      #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!\n");
      }
    2. 用以下代码编译mylib.c

      $ gcc -fPIC -g -c mylib.c
      $ gcc -shared -o libmylib.so.1.0.1 mylib.o -lc
    3. 设置LD_PRELOAD

      export LD_PRELOAD=./libmylib.so.1.0.1
    4. 最后,在上面的动态链接库 libmylib.so.1.0.1的相同目录下编译以下程序 myprog.c

      /* myprog.c */
      #include <unistd.h>
      int main()
      {
      sleep(1);
      return 0;
      }
  2. 请在以下条件下运行 myprog,并观察发生的情况。

    1. 在seed用户下运行myprog

      异常

    2. 在seed用户下运行Set-UID root myprog

      正常

    3. 使用root用户(密码重新修改为:root),添加上述环境,运行Set-UID root myprog

      异常

    4. 新建用户user1,添加上述环境,使用seed运行Set-UID user1 myprog

      正常

    5. 使用user1运行Set-UID user1 myprog

      异常

  3. 编写程序验证子进程在什么情况才会继承 LD * 环境变量

    1. 使用myprintenv.c的副本task73_printenv.c

    2. 程序为常规程序。以seed用户更改环境变量,以seed用户执行程序。

      image-20220908094545149
      image-20220908094545149

      子进程继承了用户进程的LD_PRELOAD环境变量

    3. 程序为所有者为root的Set-UID 程序。以seed用户更改环境变量,以seed用户执行程序。

      image-20220908100227920
      image-20220908100227920

      父进程和子进程都没有继承该变量

    4. 程序为所有者为root的Set-UID 程序。以root用户更改环境变量,以root用户执行程序

      image-20220908101113375
      image-20220908101113375
    5. 程序为所有者为user1的Set-UID程序。以seed用户执行程序。

分类:

后端

标签:

后端

作者介绍

mykaneki
V1