Quiet
  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT

Ram

  • HOME
  • ARCHIVE
  • CATEGORIES
  • TAGS
  • LINKS
  • ABOUT
Quiet主题
  • 软件安全
  • 环境变量

Environment Variable and Set-UID Program Lab

Ram
SeedLabs2.0

2025-11-01 21:51:09

文章目录
  1. Environment Variable and Set-UID Program Lab
    1. Task 1: Manipulating Environment Variables
    2. Task 2: Passing Environment Variables from Parent Process to Child Process
    3. Task 3: Environment Variables and execve()
    4. Task 4: Environment Variables and system()
    5. Task 5: Environment Variable and Set-UID Programs
    6. Task 6: The PATH Environment Variable and Set-UID Programs
    7. Task 7: The LD PRELOAD Environment Variable and Set-UID Programs
      1. 1.myproc为普通程序,并以普通用户运行
      2. 2.myprog 设置为 Set-UID root 程序,并以普通用户运行
      3. 3.myprog 设置为 Set-UID root 程序,在 root 账户中设置 LD_PRELOAD 环境变量后运行该程序。
      4. 4.myprog 设置为 Set-UID user1 程序,在 user2中设置 LD_PRELOAD 环境变量后运行该程序。
    8. Task 8: Invoking External Programs Using system() versus execve()
    9. Task 9: Capability Leaking
  2. 实验总结

Environment Variable and Set-UID Program Lab

Task 1: Manipulating Environment Variables

1.打印当前的环境变量,并查找PWD。

image.png

2.设置一个环境变量rwb=111,查看输出。取消这个环境变量。

image.png

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

task2的代码如下。首先输出子进程的环境。

image.png

image.png

修改代码。输出父进程的环境。

image.png

image.png

diff两个输出文件,发现没有区别。fork()是创建进程函数。程序一旦开始运行,就会产生一个进程,当执行到 fork()时,就会创建一个子进程。此时父进程和子进程是共存的,它们会一起向下执行程序的代码。通过修改 printenv 的执行位置,构造出 child1(子进程的环境变量)和 child2(父进程的环境变量) 。可以明确的是,子进程会继承父进程的环境变量。

image.png

Task 3: Environment Variables and execve()

程序如图所示,发现没有打印环境。

image.png

image.png

更改代码之后结果如下。

image.png

image.png

execve()函数接收三个参数:1.执行程序的路径;2.调用程序执行的参数序列;3.传入新程序的环境变量。若成功不返回,失败返回-1。前者第三个参数传递的是NULL,所以打印为空。后者传递了外部环境变量数据给新程序,因此打印出了当前环境变量。

Task 4: Environment Variables and system()

task4的代码如下。

image.png

image.png

system() 函数的实现,可以发现它使用 execl() 来执行 /bin/sh,execl() 会调用 execve() ,同时将环境变量传递给这个系统调用。因此,使用 system() 时,调用进程的环境变量会传递给新程序 /bin/sh。

Task 5: Environment Variable and Set-UID Programs

task5的代码如下。

image.png

将程序编程setuid程序。并修改环境变量。

image.png

image.png

image.png

image.png

运行程序后可以看到 PATH 和rwb下有export 进去的./program ,但是LD_LIBRARY_PATH并没有显示出来。

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

task6的代码如下。

首先不改变环境变量,显示正常,调用了/bin/ls。

image.png

image.png

写一个ls程序,同时修改环境变量。发现执行的程序是我们自己的ls程序。ls.c的程序如下。

image.png

image.png

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

这个实验在macos上没有做出来,又换了ubuntu虚拟机做了。

mylic.c和myprog.c代码如下。

image.png

image.png

编译程序,并设置LD_PRELOAD环境变量。

image.png

1.myproc为普通程序,并以普通用户运行

image.png

会执行我们库中的sleep。

2.myprog 设置为 Set-UID root 程序,并以普通用户运行

image.png

sleep 1秒。

3.myprog 设置为 Set-UID root 程序,在 root 账户中设置 LD_PRELOAD 环境变量后运行该程序。

image.png

会执行我们库中的sleep。

4.myprog 设置为 Set-UID user1 程序,在 user2中设置 LD_PRELOAD 环境变量后运行该程序。

添加一个user1,然后用rwb用户去实执行这个程序。

image.png

image.png

sleep 1秒。

主要原因:动态链接器的保护机制。

当运行进程的真实用户ID与程序的拥有者的用户ID不一致时,进程会忽略掉LD_PRELOAD环境变量。只有用户自己创建的程序自己去运行,才会使用LD_PRELOAD环境变量,重载sleep函数,否则的话会忽略LD_PRELOAD环境变量,不会重载sleep函数。

  1. 普通用户(seed)下执行myprog程序,此时myprog程序的拥有者是seed,而且在seed用户下设置了环境变量,所以真实用户ID与拥有者用户ID一致,子进程会继承seed用户下的LD*环境变量,并加入共享库,执行设置的sleep函数。
  2. myprog为Set-UID 根程序,在seed用户下执行,ID不一致,所以动态链接器会忽略LD_PRELOAD环境变量,子进程不能继承seed用户下的LD*环境变量,所以正常执行sleep函数。
  3. myprog为Set-UID 根程序,并在Root用户下设置了环境变量,所以在root用户下运行myprog,ID一致,所以子进程会继承root用户下的LD_PRELOAD环境变量,并加入共享库,执行设置的sleep函数。
  4. myprog为Set-UID user1程序,在seed用户下执行也会遇到ID不一致,所以忽略环境变量,正常执行sleep函数。

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

catall.c如图所示。

image.png

image.png

/bin/bash 有某种内在的保护机制可以阻止 Set-UID 机制的滥用,为了能够体验这种内在的保护级制出现之前的情形,我们打算使用另外一种 shell 程序——/bin/zsh。在一些linux 的发行版中(Ubuntu), /bin/sh 实际上是/bin/bash 的符号链接。为了使用zsh,我们需要把/bin/sh链接到/bin/zsh。

image.png

在root下面创建了一个a.txt,然后在rwb下删除这个文件,发现并没有权限给删除掉。

image.png

image.png

利用system删除掉a.txt。

image.png

注释掉system,取消注释execve。然后编译将其设置为setuid程序。

image.png

使用system()可以成功删除不可写文件,是因为system会创建一个子进程,然后子进程会调用一个新的shell程序,而且因为task8是一个Set-UID根程序,所以在执行时会以root权限执行删除文件的命令,可以成功删除。

使用execve()不可以成功删除不可写文件,因为execve会执行一个新程序,而不会调用新的shell程序,所以将我们输入的参数仅仅当成一个字符串,不会执行命令,所以不能删除不可写文件

image.png

Task 9: Capability Leaking

cap_leak.c如图所示。

image.png

创建root用户所有权限为0644的zzz文件。

image.png

修改文件位置

image.png

image.png

发现已经写入。

image.png

运行Set-UID程序时,进程暂时获得root权限,打开zzz文件时,获得了root权限下的读写文件、向文件中添加内容的权限,当使用setuid()释放root权限时,没有释放进程已经获得的特权功能—读写文件、向文件中添加内容;导致仅仅是将程序的拥有者降为非root用户,然后进程还拥有root权限下的读写文件、向文件中添加内容的功能,所以造成了权限泄露的问题,当执行fork创建子进程后在子进程中返回0,父进程中返回子进程的PID,父进程打开文件etc/zzz后,子进程不是直接修改文件/etc/zzz,而是修改了缓冲区中的文字,即在setuid之前,zzz文件就已经被打开了,只要将语句setuid(getuid())移至调用open函数之前,就可以避免。

实验总结

本次的实验集中在setuid程序和环境变量两个部分。通过实验,我更加深入理解了setuid程序是怎么样去执行了,同时理解了环境变量在程序执行的时候扮演着怎么样的角色。整体实验不算难,也相当于是抛砖引玉,未来可以深入学习类似的一些程序。

上一篇

Shellshock Attack Lab

©2026 By Ram. 主题:Quiet
Quiet主题