一、实验环境
VMware
SEED实验平台
二、实验步骤及结果
task 1:Manipulating Environment Variables
-
使用printenv或env打印环境变量
-
使用printenv PWD或env|grep PWD查找特定环境变量
-
使用export和unset来设置和取消环境变量
task 2: Passing Environment Variables from Parent Process to Child Process
-
编译运行myprintenv.c文件,把结果输出到child.txt文件
-
修改代码,输出父进程的环境变量,编译运行代码,把结果输出到father.txt文件
-
使用diff命令比较两次输出有什么不同
没有输出内容,说明两个文件的内容相同,说明子进程的环境变量继承了父进程的环境变量
task 3: Environment Variables and execve()
-
编译运行myenv.c程序,发现什么都没有打印出来
原因是:execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组,此程序第三个参数为NULL,所以什么也不会输出。
-
修改代码,将execve()的第三个参数改为environ全局环境变量,运行发现打印出当前进程的环境变量
-
结论:原进程将自己的环境变量通过environ变量传入exceve()函数的第三个传递给新进程新环境变量的参数,进而新的进程获取环境变量。
task 4: Environment Variables and system()
-
编译运行示例代码,观察输出结果
-
查阅资料
定义函数:int system(const char * string);
函数说明:system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
task 5: Environment Variable and Set-UID Programs
-
编译运行示例代码,打印当前进程中的所有环境变量
-
修改程序的所有权为root,形成Set-UID程序
-
在普通用户的shell中设置环境变量,执行第二步中生成的Set-UID
观察发现LD_LIBRARY_PATH没有进入子进程
解释:为了使 Set-UID 程序更加安全,不受
LD_LIBRARY_PATH
环境变量的影响,运行时的链接器或加载器(ld.so
)会忽略环境变量,如果程序是个 Set-UID 程序。
task 6: The PATH Environment Variable and Set-UID Programs
-
编写并编译示例代码
-
修改task6的所有权为root,形成Set-UID程序
-
将 /bin/sh 链接到另一个没有防止攻击的对策的 shell,修改PATH环境变量,执行task6
-
创建并编译自己的恶意程序
-
查看当前目录,添加到环境变量当中,让task6执行我们的ls程序
-
获取root权限
将/bin/sh 拷贝为当前目录下的文件ls
将当前路径添加到环境变量,运行task6即可获得root权限
task 7: The LD PRELOAD Environment Variable and Set-UID Programs
-
构建一个动态链接库。 创建以下程序,并将其命名为 mylib.c
-
使用以下命令编译上面的程序:
-
现在,设置 LD_PRELOAD 环境变量
-
最后编译下面的程序myprog,和上面的动态链接库libmylib.so.1.0.1在同一个目录下
-
完成上述操作后,请在以下条件下运行 myprog,并观察会发生什么。
-
使myprog 成为常规程序,并以普通用户身份运行它。
会执行设定的库中sleep函数
-
使myprog 成为Set-UID root 程序,并以普通用户身份运行它。
正常sleep一秒,退出程序
-
使myprog 成为Set-UID root 程序,再次在root 用户中设置LD_RELOAD 环境变量,然后运行它。
执行库中的sleep函数
-
使 myprog 成为 Set-UID user1 程序(即所有者是 user1,这是另一个用户帐户),在不同用户的帐户(非 root 用户)中再次导出 LD PRELOAD 环境变量并运行它。
首先创建用户user1
设置程序的所有者为user1,并设置为Set-UID程序
在seed用户中添加环境变量,执行myprog,结果是正常执行sleep,睡眠一秒然后退出程序。
-
-
设计一个实验找到上述行为不同的原因
-
使用task2中的程序,通过改变注释行可以分别打印子进程的环境变量和父进程的环境变量。
-
程序为常规程序。以seed用户更改环境变量,执行程序。
结果发现父进程和子进程的环境变量相同,且都有LD_PRELOAD环境变量,说明子进程继承了父进程的LD_PRELOAD环境变量
-
把程序设置为root的Set-UID程序,在seed用户中设置环境变量,执行程序
结果发现在子进程中没有LD_PRELOAD环境变量,只有在父进程中才能发现LD_PRELOAD环境变量,说明子进程没有继承父进程的LD_PRELOAD环境变量
-
把程序设置为root的Set-UID程序,在root中设置环境变量,执行程序
-
在root下执行
结果中子进程和父进程的环境变量相同,且都有LD_PRELOAD环境变量,说明子进程继承了父进程的LD_PRELOAD环境变量
-
在seed中执行
结果表明父进程和子进程都没有环境变量LD_PRELOAD,原因是环境变量是在root中设置的,如果有说明上一步中的seed下的环境变量没有删掉。
-
-
程序为所有者为user1的Set-UID程序。以seed用户执行程序。
结果发现在子进程中没有LD_PRELOAD环境变量,只有在父进程中才能发现LD_PRELOAD环境变量,说明子进程没有继承父进程的LD_PRELOAD环境变量
-
主要原因:动态链接器的保护机制。
当运行进程的真实用户ID与程序的拥有者的用户ID不一致时,进程会忽略掉父进程的LD_PRELOAD环境变量;若ID一致,则子进程会继承此时运行进程的真实用户下的LD_PRELOAD环境变量,并加入共享库。在此实验中设置为Set-UID程序时,在其他用户下执行,ID不一致,子进程不会继承父进程的环境变量
-
task 8: Invoking External Programs Using system() versus execve()
-
编译catall.c程序,使其成为一个root拥有的Set-UID程序
-
用root权限创建test目录下面test.txt文件,使用seed用户发现不能删除
-
通过传入多条命令来获取root权限的shell,删除文件
-
注释:掉system(command)语句,取消execve()语句的注释,重新编译运行,发现攻击失败,原因是execve不会调用shell,只会创建一个新程序,把我们传入的参数当一个字符串执行
Task 9:Capability Leaking
-
以root权限创建etc文件夹,文件夹内创建zzz文件,并设置其权限为0644
-
修改代码,把路径设置为创建的zzz文件的位置
-
编译代码,设置为所有者为root的Set-UID程序
-
在seed用户下运行,写入zzz:
-
解释:
运行Set-UID程序时,进程暂时获得root权限,打开zzz文件时,获得了root权限下的读写文件、向文件中添加内容的权限,当使用setuid()释放root权限时,没有释放进程已经获得的特权功能—读写文件、向文件中添加内容。只要将语句setuid(getuid())移至调用open函数之前,就可以避免。