Task1:

使用 printenv 或env 命令打印环境变量。

(补充可打印特殊环境变量printenv PWD或 env | grep PWD)

Printenv PWD, env |grep PWD

用export 或者 unset 去设置或者删除环境变量

Task2:

编译myprintenv.c, 运行且将结果保存到file,“a.out>file”

注释掉子进程里的 printenv()Line①,但不注释父进程的。重新编译查看结果,并保存到另一个文件

运行,./a.out

子进程是父进程的副本,它将获得父进程的环境变量、数据空间、堆、栈等资源的副本。但是,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间,它们之间共享的存储空间只有代码段。

用diff命令比较两个文件的结果,得出结论

File:

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

两个二进制文件相同,diff就什么也不显示。

结论:两次的输出相同,一次是父进程的输出,一次是子进程的输出。结合说明文档,可以看出父子进程有着相同的环境变量。

Task3  execve()

请编译并运行以下程序,并描述您的观察结果。这个程序简单地执行一个名为/usr/bin/env的程序,它打印出当前进程的环境变量。

结果:无输出   ,传递给文件的新环境变量数组为NULL,所以没有环境变量被打印出来

将第一行改成execve("/usr/bin/env", argv, environ)

给出结论,一个新的程序怎样得到他的环境变量。

函数定义 int execve(const char *filename, char *const argv[ ], char *const envp[ ]);

返回值:函数执行成功时没有返回值,执行失败时的返回值为-1.

函数说明:execve()

第一个参数filename:指向要运行的新程序的路径,

第二个参数argv:包含新程序的所有参数,

第三个参数envp:包含新程序的环境变量

  新程序通过第三个参数获得环境变量数组。且调用execve()之后,会转到新的进程,自己会被“杀死”,也就是execve()函数之后代码都不会被执行

Task4    system()

system()实际上执行“/bin/sh -c command”,即,它执行/bin/sh,并请求shell执行该命令

查看system()函数的实现,将看到它使用execl()来执行/bin/sh; excel()调用execve(),将环境变量数组传递给它。因此,使用system(),调用过程的环境变量被传递给新的程序/bin/sh。

编译运行一下程序:

与env命令结果相同,可以打印出所有环境变量,说明system函数会将环境变量传递给新程序.

system()运行原理:

实际上system()函数执行了三步操作:

1、 fork一个子进程;

2、 在子进程中调用exec函数去执行command;

3、 在父进程中调用wait去等待子进程结束。

若fork失败,system()函数返回-1。如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。(注意,command顺利执行不代表执行成功,例如command:“rm debuglog.txt”,不管文件存不存在该command都顺利执行了)如果exec执行失败,也即command没有顺利执行,比如信号被中断,或者command命令根本不存在,system()函数返回127,如果command为NULL,则system()函数返回值非0,一般为1。

Task5 Set UID

写如下程序,打印所有的环境变量

结果与env指令相同

将owner改为root,将进程改为特权程序

在Bash shell中在一个普通用户帐户中),使用export命令设置以下环境变量(它们可能已经存在):

• PATH

• LD LIBRARY PATH

• ANY NAME (this is an environment variable defined by you, so pick whatever name you want)

export PATH=/tmp:$PATH

export LD_LIBRARY_PATH=/tmp:$LD_LIBRARY_PATH

export test=12345

这些环境变量是在用户的shell进程中设置的。现在,在shell中从步骤2运行Set-UID程序。在shell中键入程序的名称之后,shell将派生子进程,并使用子进程运行程序。检查在shell进程(父进程)中设置的所有环境变量是否进入set-uid子进程。

root属的task5查找不到LD_LIBRARY_PATH路径,但PATH与自定义路径均查找成功

结论:task5被设定为setuid程序,可以提权为root用户,所以在执行env程序时Ubuntu16执行保护程序,将关键路径(LD_LIBRARY_PATH)过滤掉了。这是系统的一种保护策略,在普通用户的状态下,修改 LD_LIBRARY_PATH,如果这个修改能传递到 set-uid 程序中,那么我们就能通过修改 LD_LIBRARY_PATH 来改变 set-uid程序的库的寻找位置来实施攻击。

Task6

在Ubuntu 20.04(以及之前的几个版本)中,/bin/sh实际上是一个符号链接指向/bin/dash。 这个shell程序有一个反措施来防止自己在Set-UID进程中执行。 基本上,如果dash检测到它是在Set-UID进程中执行的,它会立即将有效用户ID更改为进程的实际用户ID,本质上就是删除特权。由于我们的受害者程序是一个Set-UID程序,/bin/dash中的对策可以阻止我们的攻击。 为了了解我们的攻击在没有这样的对策的情况下是如何工作的,我们将把/bin/sh链接到另一个shell。我们在Ubuntu中安装了一个名为zsh的shell程序 。使用以下命令将/bin/sh链接到/bin/zsh:

1、将bin/sh链接到bin/zsh(为了使用没有保护机制的shell)

2、编译并运行task6.c

3、编译,并将用户改成 root,设置 set-uid,再将程序 /bin/sh 拷贝到 /tmp目录下,并重命名为 ls,最后修改环境变量PATH, 添加目录/tmp

Cp行:将/bin/sh程序复制到/tmp目录下,并重命名为ls;

Export:修改环境变量,将tmp放到PATH开头,最先被搜索

打印发现路径修改成功

4、再次运行发现得到了有root权限的shell

打印id发现,euid为0,即说明该进程拥有root权限。

将自己编译的文件代替/bin/ls,可行的方式就是将该文件的路径搜索优先级提高到/bin/ls前,这里将/bin/zsh代替/bin/sh,以ls命名放入/tmp,并将/tmp路径加入PATH最高优先搜索路径。临时环境变量指向自己定义的ls程序,而实际是zsh程序。因为root权限执行zsh所以得到了有root权限的shell

注意:

在实验中,我们将ls 命令执行的PATH进行了修改,所有后续我们ls命令将会不可用,但是,由于export命令设置的环境变量仅适用于此shell,所以我们可以关闭shell,再重新打开,PATH就会恢复默认值了.

Task7

一般情况下,动态库加载的加载顺序为LD_PRELOAD>LD_LIBRARY_PATH>/etc/ld.so.cache>/lib>/usr/lib

Step1:

1、构建一个动态链接库。创建下面的程序,命名为mylib.c。它基本上重写libc中的sleep()函数:

2、用以下命令编译

gcc -fPIC -g -c mylib.c

gcc -shared -o libmylib.so.1.0.1 mylib.o -lc

3、设置环境变量

export LD_PRELOAD=./libmylib.so.1.0.1

4、编译下面的程序myprog,并将其放在与上述动态程序相同的目录中链接库

libmylib.so.1.0.1:

Step2:完成以上步骤后,在不同情况下运行myprog程序,观察结果。

1、使myprog成为一个常规程序,并以普通用户的身份运行它。

2、将myprog设置为Set-UID根程序,并以普通用户的身份运行

正常执行,pause1秒,退出程序。动态链接器实现了一些防御策略。

3、使myprog成为Set-UID根程序,以root身份再导出LD_PRELOAD环境变量,并运行它。

export LD_PRELOAD=./libmylib.so.1.0.1

4、将myprog设置为Set-UID user1程序(例如,所有者是user1,这是另一个用户帐户),在另一个用户(非root用户)的帐户中再次导出LD PRELOAD环境变量运行它。

创建用户并运行:

设置成set uid程序,并再次导出LD PRELOAD环境变量运行它。

Step3:

验证:

打印子进程的环境变量,看是否是因为子进程不继承LD_PRELOAD变量,导致的结果不同。

编译:

export LD_PRELOAD=./libmylib.so.1.0.1

1、普通身份下运行:

继承了环境变量,攻击能成功。

2、普通用户(seed)身份运行Set-UID root程序test

没有继承环境变量,因此调用系统中的函数。

3、root用户身份,export  LD_PRELOAD,运行Set-UID root程序test。

环境变量被导入

4、普通用户身份,export  LD_PRELOAD,运行Set-UID seed程序test。

默认情况下,sleep()函数被动态链接,程序运行时,动态连接器会在libc.so库中查找该函数(sleep是这个共享库中的函数)。LD_PRELOAD环境变量可以让连接器将SLEEP函数和用户代码链接在一起,而不是libc.so中的sleep。

可见,如果程序为设置了Set-UID的程序,运行时不会出现函数重载,即运行myprog程序的子进程不继承LD_PRELOAD变量。RUID(真实用户ID)和EUID(有效用户ID)不同时,可能会触发链接器的保护机制,会忽略导入的LD_PRELOAD环境变量,正常执行sleep(1)的操作。

Task8:

Step1:

1、编译上面的程序,把它的所有者变成它的所有者,并将它更改为一个Set-UID程序。

  1. 运行:
  2. 2、 在root下创建文件,只有root有权限删除。
  3. 在root用户下,创建(mkdir)一个文件夹ttt8。
  4. 在root用户下,ttt8文件夹中(cd),新建(touch)一个task8文件。

在seed下删除失败:

用Set-UID root程序catlall来删除task8文件夹下的task文件,成功

Step2:

1、注释掉system(command)语句,并取消execve()语句;该程序将使用execve()来调用该命令。编译程序,并使之成为Set-UID(由root拥有)。你在步骤1中的攻击仍然有效吗?请描述并解释你的观察。

删除失败:


system()函数实现原理见task4。Step1中相当于执行:/bin/cat ./ttt.c;rm ./ttt.c,分号将命令分为两句,但由于都是system()创建的子进程执行,拥有root权限,所以ttt.c文件被成功删除。

execve()函数实现原理见task3。Step2中由于是获得的字符串数组,” ./ttt.c;rm ./ttt.c”被当做一个字符串元素,cat程序执行查找不到这个文件,所以攻击失败。

在前面写到过,实际上system()函数执行了三步操作:

1 fork一个子进程;

2 在子进程中调用exec函数去执行command;

3 在父进程中调用wait去等待子进程结束。

在第二步中,引入了外部程序shell,而在shell中,是可以执行任何指令的,所以,我们可以执行多条指令,在设置setuid程序后,可以获取root权限.

而execve函数为执行一个系统调用函数

int execve(const char *filename, char *const argv[],char *const envp[]);

第二个参数中如果包含额外的指令,他们仍然会被视为一个参数,并非一个指令.所以才会出现:

/bin/cat: ‘secret;/bin/sh’: No such file or directory

的错误,secret;/bin/sh被视为了一个字符串参数.

system()函数违背了最小权限原则,调用了shell,而shell可以执行任意命令.以及输入验证原则,过分信任了用户的输入.所以,system()函数需要谨慎使用,推荐使用execve()函数,进行了运行程序与程序参数的分类,更安全.

Task9: 权限泄露

编译以下程序,将其所有者更改为root,并将其设置为Set-UID程序。以普通用户的身份运行程序,并描述您所观察到的情况。文件/etcIzzz会被修改吗?请解释你的观察。

1、root用户下(sudo su),在/etc(cd /etc)中新建文件zzz(touch zzz),并在zzz文件里写入内容。

2、将cap_leak修改为root,赋予SUID特殊权限。

3、尝试直接写入失败。

4、运行capleak,获得文件描述符进入SHELL程序

分析其原因是因为其在取消权限前并没有关闭文件,导致seed用户仍然可以进行root用户才可以执行的写入操作。如果需要防止权限泄露这种情况的发生,我们需要在退出root前,修改task9和/etc/zzz的权限,将其修改为其他组不可读取不可写不可执行;或者在程序中将setuid这类语句注释掉,防止在普通用户使用过程中获得特殊权限。

Lab12_Environment_Variable相关推荐

最新文章

  1. 没有有效IP配置,无Internet访问,未识别的网络解决方法
  2. Avahi DOS攻击broadcast-avahi-dos
  3. centos7挂载windows共享文件夹
  4. usg2130 虚拟服务器,usg2130防火墙怎么样设置
  5. Android学习笔记:对Android应用进行单元测试
  6. Eclipse最常用快捷键
  7. 数据结构与算法--1.整型变量值互换
  8. android 查询wifi信息的类,Android 获取wifi信息
  9. java包资源_Java获取jar包以外资源的方法
  10. 【我的Android进阶之旅】Realm数据库学习资料汇总(持续更新)
  11. 更改网页alert弹出框样式
  12. mysql二级软件_全国计算机等级考试二级MySQL练习软件
  13. Php-fpm没生成sock,PHP-FPM无法生成.sock文件
  14. C++ MFC 如何画一个空心的即透明填充色的图形如矩形,圆形等
  15. 每日一学33——Unity点击UGUI按钮后,再按空格键会自动触发按钮
  16. 快速定位线上慢 SQL 问题,掌握这几个性能排查工具可助你一臂之力
  17. Java 11~~20
  18. LeetCode第258场周赛
  19. rbf神经网络自适应控制matlab仿真,机械系统RBF神经网络控制:设计、分析及Matlab仿真(英文)...
  20. 使用每篇等工具进行图文编辑

热门文章

  1. 图片怎么压缩到100k以下?
  2. python android 扩展库,Python模块进阶、标准库、扩展库
  3. 什么是电子面单,电子面单的功能和应用场景
  4. 使用graphhopper(map-matching)进行地图匹配
  5. 《算法第四版》官方jar包中In的readStrings()方法不建议使用的解决办法
  6. 阿里云OSS对象存储 , js 上传文件
  7. linux下c的串口收发
  8. MathJax使用LaTeX语法编写数学公式
  9. 医院选址问题 C++ 弗洛伊德
  10. 曲面触摸传感器设计的挑战