Environment Variable and Set-UID Program Lab

Environment Variable and Set-UID Program Lab

Task 1: Manipulating Environment Variables

  • 使用 printenv 或 env 命令打印出环境变量。 如果您对某些特定的环境变量(例如 PWD)感兴趣,可以使用“printenv PWD”或“env | grep PWD”。

image-20211020145822500

  • 如果您对某些特定的环境变量(例如 PWD)感兴趣,可以使用“printenv PWD”或“env | grep PWD”。

image-20211020145903437

  • 使用 export 和 unset 来设置或取消设置环境变量。 需要注意的是,这两个命令不是单独的程序; 它们是 Bash 的两个内部命令(您将无法在 Bash 之外找到它们)。

image-20211020150046782

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

  • Step1:编译并运行以下程序

image-20211020151247295

  • 这将生成一个名为 a.out 的二进制文件。 让我们运行它并使用“a.out > file”将输出保存到一个文件中。

image-20211020151339380

image-20211020151502197

image-20211020151557465

image-20211020151921417

diff命令没有输出,表示内容相同。

Task 3: Environment Variables and execve()

image-20211020152709997

  • Step1:这个程序只是执行一个名为/usr/bin/env 的程序,它打印出当前进程的环境变量。发现执行结果为空。
1
int execve(const char * filename,char * const argv[],char * const envp[])
  • 第一个参数为一个可执行的有效的路径名。第二个参数argv系利用数组指针来传递给执行文件,v是要调用的程序执行的参数序列,也就是我们要调用的程序需要传入的参数;envp则为传递给执行文件的新环境变量数。
  • 所以在此处,我们赋予新进程的环境变量为空,自然印出环境变量结果为空。
  • Step2:将第①行中 execve() 的调用更改为以下内容; 描述你的观察。

image-20211020153026820

image-20211020153311871

  • 结论:execve()产生的新进程的环境变量需要在调用时进行传递。

Task 4: Environment Variables and system()

image-20211020154103500

1
int system(const char * string)

system()调用fork()函数新建一个子进程;在子进程中调用execl()函数去执行command;在父进程中调用wait去等待子进程结束。

Task 5: Environment Variable and Set-UID Programs

  • Step1:编写程序,可以打印出当前进程中的所有环境变量

image-20211020224003336

  • Step2:编译上述程序,将其所有权改为root,并使其成为Set-UID程序。

image-20211020224014380

  • Step3:在您的 shell 中(您需要使用普通用户帐户,而不是 root 帐户),使用 export 命令设置以下环境变量(它们可能已经存在):

image-20211021100901489

image-20211021100901489

  • 找不到LD_LIBRARY_PATH(主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径):

    为了使 Set-UID 程序更加安全,不受LD_LIBRARY_PATH环境变量的影响。如果程序是个 Set-UID 程序 ,运行时的链接器或加载器(ld.so)会忽略该环境变量,

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

  • 新建并编译所给程序task6.c和恶意程序fake_ls.c

image-20211020234105932

image-20211020235045011

image-20211020235045011

image-20211021104619050

  • 将task6设置为setuid程序

image-20211021103533207

  • 查看当前目录的路径,通过export设置PATH先查找当前目录。

image-20211021103317949

  • 将 /bin/sh 链接到另一个没有防止攻击的对策的 shell;编译生成自己的ls,运行task6。

image-20211021104005806

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

Step1:

  • 构建一个动态链接库。 创建以下程序,并将其命名为 mylib.c

image-20211021110714056

  • 使用以下命令编译上面的程序:

    image-20211021111108716

  • 现在,设置 LD_PRELOAD 环境变量:

    image-20211021164256576

  • 最后编译下面的程序myprog,和上面的动态链接库libmylib.so.1.0.1在同一个目录下:

    image-20211021164338809

Step2:完成上述操作后,请在以下条件下运行 myprog,并观察会发生什么。

  • 使myprog 成为常规程序,并以普通用户身份运行它。

    会执行我们设定的库中的sleep函数,输出字符串。

    image-20211021164407880

  • 使myprog 成为Set-UID root 程序,并以普通用户身份运行它。

    正常执行程序,sleep 1秒,然后退出程序。

    image-20211021164659198

  • 使myprog 成为Set-UID root 程序,再次在root 用户中设置LD_RELOAD 环境变量,然后运行它。

    首先登入root用户,设置LD_PRELOAD 环境变量:

    image-20211021165141482

    • 以root用户运行:

      会执行我们设定的库中的sleep函数,输出字符串。

      image-20211021165313056

    • 以普通用户运行:

      正常执行程序,sleep 1秒,然后退出程序。

      image-20211021165406084

  • 使 myprog 成为 Set-UID user1 程序(即所有者是 user1,这是另一个用户帐户),在不同用户的帐户(非 root 用户)中再次导出 LD PRELOAD 环境变量并运行它。

    • 首先新建用户user1:

    image-20211021165729604

    • 设置程序的所有者为user1,并设置为Set-UID程序,并设置环境变量

    image-20211021165838025

    • 以seed用户运行该程序:

      正常执行程序,sleep 1秒,然后退出程序。

      image-20211021165939108

  • Step3

    设计一个实验来找出并解释Step2中的行为不同的原因。

    • 编写并编译程序:print_env,通过改变注释行可以分别打印子进程的环境变量和父进程的环境变量。

      ![image-20211021214959424](软件安全Lab1/image-20211021214959424.pngimage-20211021215250109

      image-20211021215130804

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

      image-20211021220918021

      • 子进程与父进程环境变量相同,且含LD_PRELOAD,即子进程继承了用户进程的LD_PRELOAD环境变量。

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

      image-20211021221304514

      • 父进程的环境变量可以发现LD_PRELOAD环境变量,而在子进程的环境变量中找不到,即子进程没有继承用户进程的LD_PRELOAD环境变量。

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

      • 以root用户运行:

        image-20211021221853609

        • 子进程与父进程环境变量相同,且含LD_PRELOAD,即子进程继承了用户进程的LD_PRELOAD环境变量。
      • 以seed用户运行:

        image-20211021222645489

        • 父进程的环境变量可以发现LD_PRELOAD环境变量,而在子进程的环境变量中找不到,即子进程没有继承用户进程的LD_PRELOAD环境变量。

      ④程序为所有者为user1的Set-UID程序。以seed用户执行程序。

      image-20211021222930510

      • 父进程的环境变量可以发现LD_PRELOAD环境变量,而在子进程的环境变量中找不到,即子进程没有继承用户进程的LD_PRELOAD环境变量。
    • 主要原因:动态链接器的保护机制

      当运行进程的真实用户ID与程序的拥有者的用户ID不一致时,进程会忽略掉父进程的LD_PRELOAD环境变量;若ID一致,则子进程会继承此时运行进程的真实用户下的LD_PRELOAD环境变量,并加入共享库。

Task 8: Invoking External Programs Using system() versus execve()

新建一个目录t8,在该目录下创建test.txt文件。

image-20211021225248348

对于普通用户,test.txt是不可写的,尝试删除它,但权限不够

image-20211021225330635

  • **Step1:**编译上述程序,使其成为一个root拥有的Set-UID程序。 该程序将使用 system() 来调用该命令。

image-20211021223845839

image-20211021225640642

通过catall得到了root权限的shell,成功删除test.txt。

  • **Step2:**注释掉system(command)语句,取消execve()语句; 程序将使用 execve() 来调用命令。

image-20211021230139268

攻击失败。因为execve会执行一个新程序,而不会调用新的shell程序。

Task 9: Capability Leaking

  • 以root用户创建一个etc文件夹,文件夹内创建zzz文件,并设置其权限为0644。

image-20211021230708725

  • 更改cap_leak.c下zzz的路径

    image-20211021232010820

  • 编译cap_leak.c,设置为Set-UID root程序。

    image-20211021231031083

  • 在seed用户下运行,写入zzz:

    image-20211021233542812


本博客所有文章除特别声明外,均为博客作者本人编写整理,转载请联系作者!