(SEED-Lab)Environment Variable and Set-UID Program Lab
Environment Variable and SEED-UID Program Lab(SEED-Lab)欢迎大家访问我的GitHub博客https://lunan0320.cn文章目录一、实验目的二、实验步骤与结果Task 1: Manipulating environment variablesTask 2: Passing Environment Variables from Paren
(SEED-Lab)Environment Variable and SEED-UID Program Lab
欢迎大家访问我的GitHub博客
https://lunan0320.cn
文章目录
- 一、实验目的
- 二、实验步骤与结果
- Task 1: Manipulating environment variables
- Task 2: Passing Environment Variables from Parent Process to Child Process
- Task 3: Environment Variables and execve()
- Task 4: Environment Variables and system()
- Task 5: Environment Variable and Set-UID Programs
- Task 6: The PATH Environment Variable and Set-UID Programs
- Task 7: The LD PRELOAD Environment Variable and Set-UID Programs
- Task 8: Invoking External Programs Using system() versus execve()
- Task 9: Capability Leaking
- 三、参考文献
一、实验目的
1、了解环境变量如何影响程序和系统行为
2、了解环境变量是如何工作的
3、环境变量如何从父进程传播到子进程,以及它们如何影响系统和程序行为
4、学习如何安全调用外部程序,如何处理权限泄露及动态加载与链接的问题
二、实验步骤与结果
Task 1: Manipulating environment variables
使用printenv命令查看PATH环境变量,env |grep PWD命令过滤输出环境变量
此处需要先通过export添加环境变量,然后通过unset命令删除环境变量
export 添加环境变量 tmp_env=123456
Unset 删除环境变量 tmp_env=123456
可以看到,当使用printenv命令查看环境变量,并对其进行过滤之可以成功完成添加和删除环境变量操作。
Task 2: Passing Environment Variables from Parent Process to Child Process
Step1
编辑并编译Task2.c文件,将其运行结果输出到Task2.1.txt文件中
Step2
注释掉(1)处代码,执行(2)处代码,再次编译并运行,将结果保存到了Task2.2.txt
Step3
比较二者的不同,使用的是diff命令比较两个输出文件的不同。可以看到,子进程继承了父进程的全部环境变量。
Conclusion:
diff命令执行后提示在68c68是在第一个文件的68行与第二个文件的68行处有所不同,<后是第一个文件中68行处的内容,>后表示的是第二个文件中68行处的内容。
可以看出,子进程与父进程相比,继承了父进程的环境变量。唯一的不同是可执行程序的用户名不同而已。
Task 3: Environment Variables and execve()
Step1
编辑程序,并在gcc下编译该c程序。
编辑完成之后,发现报错,提示缺少函数声明。查阅资料后得知,需要添加头文件#include<unistd.h>
重新编译后发现可以成功运行,但是在terminal中没有执行结果打印出来。
此时由于execve函数中传递的环境变量为NULL,没有输出值。
Setp2
将程序中的exexve()函数换成 execve("/usr/bin/env", argv, environ),在第三个参数位置传入environ(全局环境变量)。
修改execve()函数的参数NULL之后,可以成功编译并执行,打印出了当前的环境变量。
Setp3
此时可以得出结论,第一次实验中,发现没有打印出环境变量,这是因为在执行execve()函数时,传递了一个NULL的参数,自然不会有什么打印结果。
当在execve()函数中,传递了全局环境变量environ时候,可以成功将传递进去的环境变量打印出来。
Task 4: Environment Variables and system()
Conclusion:
查阅资料后得知,system()函数实质是使用execl()函数生成子进程调用了/bin/sh,然后通过/bin/sh来在shell中执行,这个过程中execl()是调用了execve()函数,当在system中传入参数/usr/bin/env之后,即相当于将环境变量传入了execve()函数,因此,system()函数可以成功执行打印了环境变量。
Task 5: Environment Variable and Set-UID Programs
Step1
创建Task5.c文件,写入如下代码,依次打印环境变量。
Step2
编译该程序,在执行step2中指令之前,先查看一下当前Task5.c文件的用户以及模式。如下。
此时,更改Task5的有效用户为root,以及设置了Set_UID的比特位,再次查看Task5文件的权限,可以对比在更改之前的权限。
Step3
未修改之前,运行程序,查看当前环境变量。
执行step3中的步骤,执行export命令,路径为/home/seed/,其中,自定义的环境变量命名为ADD_PATH
执行之后,过滤其中含有PATH的路径,可以看到,其中PATH以及自定义的环境变量ADD_PATH均成功执行,但是LD_LIBRARY_PATH的环境变量并没有显示出来。
对LD_LIBRARY_PATH的环境变量单独过滤。
可以看到,依然是没有成功显示出来,对此,一直认为是没有成功export的原因,后续查阅资料后得知。这是因为动态链接器的保护机制,设置LD_LIBRARY_PATH环境变量其实就是设置动态库的查找路径,而这是不会出现在子进程的环境变量中的,这样一来子进程是看不到的。
了解到,根据动态链接库的防御机制,在编译后设置了该程序的有效ID为root,而在普通用户shell中运行时,真实用户为seed,因此此处设置的环境变量被忽略,没有起作用。
但是当直接在shell中打印该环境变量,可以看到,成功显示。
Task 6: The PATH Environment Variable and Set-UID Programs
Task6.c程序如下:
根据Note部分得知,此处需要将/bin/sh链接到/bin/zsh方可正常进行。
在seedUbuntu 16.04中,bash解释器有一个保护机制,当它发现自己是在一个Set-UID进程运行时,会立即将有效用户ID变成实际用户ID,主动放弃特权
/bin/ls为一个软链接,所以实验前需要确保/bin/目录下的sh创建软链接到zsh,而不是bash.
查看/bin目录下的sh程序文件
将/bin/sh软链接到 /bin/zsh
在未设置Set_UID程序之前,正常执行ls命令
将Task6设置为root用户下的Set_UID程序
查看/bin文件下的pwd命令,对ls命令的使用转换到对pwd命令上。
将/bin/pwd命令程序复制到/home/seed/Desktop/Lab1目录下,并命名为ls
修改PATH环境变量,将/home/seed/Desktop/Lab1加入到PATH环境变量的开头,因此在执行命令时候,会优先到/home/seed/Desktop/Lab1目录下寻找。
在Task6.c程序中,执行system(“ls”)命令,其中ls将会直接去/home/seed/Desktop/Lab1目录中查找。而我们已经把pwd程序复制到该目录下的ls程序中,因此执行Task6时,程序相当于执行了一次pwd操作.
运行Task6程序:可以看到,并没有执行ls命令的效果,但是执行了pwd命令的效果,程序运行了指定的shell程序/bin/sh。由于Task6为Set_UID程序,有效用户为root,显然在执行过程中是以root权限执行了。
此处即实现了用Set_UID程序来运行自己代码的效果。
Task 7: The LD PRELOAD Environment Variable and Set-UID Programs
Step1
Step1.1
编辑mylib.c程序如下
Step1.2 &Step1.3
将mylib.c编译为libmylib.so.1.0.1动态链接库
同时根据提示,设置LD PRELOAD环境变量
Step1.4
编辑并编译myprog.c程序,如下
Step2
1、regular program & normal user.
很短时间内直接打印输出结果,说明此时sleep函数是与自定义的动态链接库链接到了一起。
2、Set-UID root program & normal user
将myprog程序的owner有效使用者改为root,设置为Set_UID程序。
此时,即实现了Set_UID root程序,普通用户的环境。
重新运行程序,此时,程序运行大概1s之后结束,但是没有任何输出结果。
3、Set-UID root program & export LD PRELOAD env & root account
先将用户权限提升至root用户,再增加LD_PRELOAD的环境变量,查看环境变量可以看到设置成功。
此时运行myprog程序,程序没有等待1s时间,直接打印出结果。
4、Set-UID user1 program & different user & export LD PRELOAD env
之前的Set_UID程序为user1,此时将user2设置为lunan,在此用户下运行
尝试为myprog更改用户lunan,直接更改出错,因此在系统中考虑新建一个用户。
使用sudo adduser lunna命令
切换到lunan用户,可以看到myprog的有效用户依然是root,此处需要将其调整为user2即lunan,即直接使用chown命令即可。
但是由于lunan用户未添加如sudoers 文件,因此,此处需要先将lunan用户添加到sudoers文件中
过程如下,在root用户下对sudoers文件进行更改,更改完成后还原保留原文件权限。
在sudoers文件中添加lunan用户
完成后即可在user2即lunan用户下更改myprog文件的有效用户
运行程序发现,等待1s之后没有任何输出结果
Step3
分析,查阅资料后了解到LD_PRELOAD变量的保护策略,是通过链接。使用gcc的-static参数可以把libc.so.6静态链入执行程序中。但这也就意味着程序不再支持动态链接。
通过设置执行文件的setgid /setuid标志,在有Set-UID权限的执行文件,系统会忽略LD_PRELOAD环境变量。也就是说,如果你有以root方式运行的程序,最好设置上SUID权限.如:chmod 4755 myprog
分析:
1中,有效用户和真实用户均为seed,因此并没有忽略自定义的环境变量LD_PRELOAD,此时链接到的是自定义的动态链接库,ibmylib.so.1.0.1,输出打印结果。
2中,有效用户为root,真实用户为seed,真实用户与有效用户不同。此时环境变量LD_PRELOAD就被屏蔽(这正是动态链接器的防御机制),链接到的是原先的标准库libc,此时执行了sleep()没有输出。
3中,有效用户和真实用户均为root,因此并没有忽略自定义的环境变量LD_PRELOAD,保护机制没有生效。此时链接到的是自定义的动态链接库,ibmylib.so.1.0.1,输出打印结果。
4中,有效用户为lunan,真实用户为seed,真实用户与有效用户不同。此时环境变量LD_PRELOAD就被屏蔽,链接到的就不是自定义的动态链接库,而是原先的标准库,此时执行了sleep()没有输出。
Task 8: Invoking External Programs Using system() versus execve()
Step1
编辑Task8.c的文件,如下。
对Task8.c程序编译后,将其有效用户设置为root,并设置为Set_UID程序。
运行Task8.c程序,可以看到能够成功执行,将所需求的文件Task8.c的内容打印出来。
在root用户情况下,在根目录下新建一个test.txt文件,此文件的所有者是root,只有root有对该文件的执行修改权限。
注意:此处必须是根目录,经实验,当在其他目录下时,即使切换到普通用户情况下,依旧可以删除。
在seed用户情况下,查看该test.txt文件、查看文件权限、删除文件这些操作都是被禁止的。
本以为在这种情况下,普通用户是无法做到这样的功能的,但是在查阅资料后发现,可以利用Task8.c的程序。
只需要在filename 的位置在Task8.c的后面接上该指令即可,如图
此时,切换到root用户下,查看test.txt文件,可以看到无此文件,即删除成功。在Task8.c的辅助下是可以删除一个不可写的文件的。
Step2
将system()函数部分注释,使用execve()函数执行。
对Task8.c程序重新运行执行,并改变其有效用户,设置Task8为Set_UID程序。运行该程序,发现是可以正常执行的。
切换到root用户下,新建测试文件test2.txt,并将其置于根目录下。查看其属性,可以看到,普通用户只有可读权限。
采用Step1中的方法删除该文件,发现是无法成功删除的,显示没有该文件或目录。
分析原因:
在system()函数中,本质上是调用shell去执行命令,此时shell独立性是比较高的,会将其分为两条命令分开执行。没有区分代码和数据。
而execve()函数中,本质上就是执行命令,此时只能执行一个进程,当作一个命令执行,这是删除失败的原因。实现了代码和数据的相隔离。
Task 9: Capability Leaking
创建/etc/zzz文件
Task9.c程序及其编译过程
为Task9赋予root有效用户以及设置为Set_UID程序
运行Task9程序,在停顿了大约1s(即代码中的sleep()函数执行)之后,程序退出。
查看/etc/zzz文件的内容,发现已经被篡改。
分析原因:
该程序是root有效用户,并是Set_UID程序,有权利打开/etc/zzz文件,在执行了setuid()撤销权限后,由于文件并没有关闭,出现了权限泄露的问题,该文件仍然具有root权限。因此能够继续执行写入Malicious Data的内容。
三、参考文献
[1]SEEDLab Environment Variable and Set-UID Program Lab
https://blog.csdn.net/C_Ronaldo__/article/details/112506896?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.no_search_link&spm=1001.2101.3001.4242
[2]Linux中的setuid简介_白熊的窝-CSDN博客
https://blog.csdn.net/weixin_44575881/article/details/86552016
[3]C 库函数 – system() | 菜鸟教程 (runoob.com)
https://www.runoob.com/cprogramming/c-function-system.html
[4]linux中execve函数的用法 - 少年努力吧 - 博客园 (cnblogs.com)
https://www.cnblogs.com/jxhd1/p/6706701.html
[5]环境变量详解(Windows&Linux) - 简书 (jianshu.com)
https://www.jianshu.com/p/4023b8783f2e
更多推荐
所有评论(0)