软件安全测试第一次实验

__姓名:secret! 班级:secret! 学号:secret!

一、实验题目

Environment_Variable_and_SetUID.pdf (seedsecuritylabs.org)

二、实验环境

Dell 14pro 灵越5410

VMware17

Ubuntu 22.04

Linux 5.19.0 x86_64

三、实验内容

1. 设置环境变量

Task 1.1

打印环境变量(截图中的输出未展示全部)

显示当前路径

Task 1.2

导入/撤销环境变量

  1. 子进程如何从父进程获取环境变量

myprinten.c

结论:结合教材所学知识,fork()创建子进程会继承父进程的环境变量,execve()调用会丢失环境变量,需要作为参数显式地传递。

  1. 环境变量受execve的影响

execve.c

(截图中的输出未展示全部)

原因分析:首先传入NULL环境变量为空,然后修改第三个参数environ显式传入成功打印环境变量

结论:execve若在一个进程中使用,环境变量会丢失,必须要作为参数显式地传递

原有进程的内存被完全替换成新程序,execve不会创建新的进程,PID没有变化,exec只是用磁盘上的新程序替换了当前进程的正文,数据,堆,栈段。所以环境变量也被替换了。

  1. 环境变量受system()影响

system.c

(截图中的输出未展示全部)

结论:可见实验中打印出所有环境变量,说明system函数会将环境变量传递给新程序

system()调用实际上是调用shell执行命令,system()的实现是用execl()系统调用来运行shell然后execve()传递环境变量数组,所以用system系统调用,当前进程的环境变量会传递给新程序。

  1. 环境变量和setuid程序

编译运行后设置为setuid程序,导入3个环境变量,再分别运行打印

结论:

所有的在父进程shell设置的环境变量都传递到了setUid程序子进程。shell中执行程序,当输入程序名称时,shell会生成一个子进程并在子进程中执行该程序.这个过程通常为先使用fork函数创建一个子进程,再使用execve()函数。

设置LD_LIBRARY_PATH环境变量(动态库的查找路径)不会出现在子进程的环境变量中,而其他两个均可以被包含。这是由于setuid程序的防御机制,当真实用户和有效用户不一致会自动忽略这个环境变量,而自定义的usrname没有危害仍可以打印

  1. PATH环境变量和setuid程序

编译运行后设置为setuid程序,将/bin/sh复制到另一个路径下并添加到环境变量,查看环境变量检查添加成功:tmp目录最先被搜索,然后运行程序,得到root权限

原因分析:虽然程序中命令为ls,但实际上运行了自己设定的程序/bin/sh,同时由于程序为Set-UID,有效用户为root,运行时以root权限运行,得到root权限的shell.

  1. LD_PRELOAD环境变量和setuid程序

Step1

进行动态链接和环境变量设置,编译源代码

Step2

情形一

常规程序,普通用户运行,执行自定义函数

情形二

设置setuid再运行,正常sleep1s后退出

情形三

在setuid基础上加入环境变量后再运行,正常sleep1s后退出

情形四:

将拥有者设置为第三方用户,成功运行重载sleep函数

设置为setuid程序再运行,不会运行重载函数:

结果分析:

动态链接器对Setuid程序有防御机制,当拥有者存在不一致时会忽略设置的环境变量;设置了Set-UID的程序,运行时不会出现函数重载

  1. 使用system()与excve()调用外部程序

Step1

编译并setuid系列操作,查看权限:

在当前目录下创建不为空文件test8。将所有者改为root并用root身份设置只读权限,(这样操作使得普通用户无法操作test8)。运行程序,查看test8内容并执行输入行指令rm test8,成功删除test8文件

Step2

注释system系统调用代码,改用execve

不会得到root权限

结果分析:

System系统调用函数实际执行三个操作:首先fork创建一个子进程;然后子进程中调用exec函数去执行command;在父进程中调用wait等待子进程结束。

其中在第二步引入了外部程序shell,(希望这个setuid执行shell:shell先被执行,command作为输入然后解析执行,是通过调用/bin/bash -c command;shell程序允许一行输入两个命令,用分号隔开),而在shell中,是可以执行任何指令的,所以实验中可以执行多条指令,在设置setuid程序后,可以获取root权限。system()函数违背了最小权限原则,调用了shell。

execve函数为执行一个系统调用函数,包含3个函数参数,其中第2个参数若包含额外指令也会被视作一个参数。

  1. 权限泄露

命令行解释:

首先以普通用户运行发现无法打开因为没有/etc/zzz的root权限

然后ls -l查看可执行文件的权限

以root身份向/etc/zzz写入,然后退出登录降低身份为普通用户

以普通用户身份写入/etc/zzz仍然没有权限

但是运行setuid程序之后,输出文件描述符并能够成功写入

结果分析:

Cap_leak.c中有打开文件open代码但是没有对应关闭文件close代码,并且setuid()撤销权限时泄露把握文件描述符的能力,也就是取消权限前并没有关闭文件,导致普通用户通过打印文件描述符fd拥有对文件操作的特权

避免方法:

法一:退出root之前,取消可执行文件cap_leak的set位权限即setuid,将/etc/zzz的权限位除拥有者root外其他用户其他组都没有任何读写执行的权限;

法二:在cap_leak.c中注释撤销权限代码setuid(),以防普通用户从中获得特殊权限。

修改后运行结果如下:

成功阻止普通用户写入

Comments

⬆︎TOP