SEED实验——Environment Variable and Set-UID Program实验报告
任务一:操作环境变量
- 实验过程一: 用printenv或env打印出环境变量。
在终端输入命令,显示结果如下图所示:
经过实验发现,printenv和env均可输出当前系统的环境变量。不同的是printenv不加参数和env一样,而printenv可以打印指定名称的环境变量。
- 实验过程二: 使用export或者unset命令设置或去掉环境变量。
任务二:集成环境变量
实验过程:child和child2文件略。
实验结论:
通过比较这两个文件,可以发现,这两个文件输出的环境变量完全相同。说明原环境变量被子进程完全继承。通过man fork,对fork函数做了进一步了解。fork函数通过系统调用创建一个与原来进程几乎完全相同的进程,子进程自父进程继承了进程的资格,环境,堆栈与内存根目录等;但是子进程没有继承父进程的某些特性,比如父进程号,文件描述符,在tms结构中的系统时间,资源使用等。
任务三:环境变量和execve()
实验过程一:编译并运行以下程序。描述观察到的实验结果。该程序简单地调用了/usr/bin/env,该系统调用能够打印出当前进程的环境变量。
#include <stdio.h>
#include <stdlib.h> extern char **environ;
int main()
{
char *argv[2];
argv[0] = "/usr/bin/env";
argv[1] = NULL;
execve("/usr/bin/env", argv, NULL);
return 0 ;
}
观察到的实验结果如图所示:
execve()
- 实验过程二:改变execve()函数的参数,描述你观察到的结果。
补充:execve()函数的使用方法:
int execve(const char * filename,char * const argv[],char * const envp[])
execve()用来执行参数filename字符串所代表的文件路径,filename必须是一个二进制的可执行文件,或者是一个脚本以#!格式开头的解释器参数。如果是后者,这个解释器必须是一个可执行的有效的路径名。第二个参数系利用数组指针来传递给执行文件,argv是要调用的程序执行的参数序列,也就是我们要调用的程序需要传入的参数。envp则为传递给执行文件的新环境变量数组,同样也为参数序列。
- 实验结论:请得出关于新程序如何获取其环境变量的结论。
任务四:环境变量和system()
- 实验过程:编译并运行以下程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("/usr/bin/env");
return 0 ;
}
运行结果为:
运行结果分析:
先看一下system()函数的简单介绍。system函数定义为 int system(const char * string),该函数调用/bin/sh来执行参数指定的命令,/bin/sh一般是一个软连接,指向某个具体的shell,比如bash,-c 选项是告诉shell从字符串command中读取命令;在该command执行期间,SIGCHLD信号会被暂时搁置,SIGINT和SIGQUIT则会被忽略,意思是进程收到这两个信号后没有任何动作。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。
具体看一下system()函数的实现:
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL)
{
return (1); //如果cmdstring为空,返回非零值,一般为1
}
if((pid = fork())<0)
{
status = -1; //fork失败,返回-1
}
else if(pid == 0)
{
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~
}
else //父进程
{
while(waitpid(pid, &status, 0) < 0)
{
if(errno != EINTR)
{
status = -1; //如果waitpid被信号中断,则返回-1
break;
}
}
}
return status; //如果waitpid成功,则返回子进程的返回状态
}
任务五:环境变量和Set-UID程序
- 实验过程一:在当前步骤中写一个能够输出所有环境变量的程序。
我写的能够传输所有环境变量的程序如下:
/************ task5.c************/
#include <stdio.h>
extern char** environ;
int main()
{
int nIndex = 0;
for(nIndex = 0; environ[nIndex] != NULL; nIndex++)
{
printf("%s\n",environ[nIndex]);
}
}
实验过程二:编译以上程序,将其权限改为roo权限,使其成为一个Set-UID程序。
使用如下命令:
chown root:root task5.c
将task5.c的权限改为root权限。实验过程三:使用一般用户登录终端,使用export命令设置如下环境变量:PATH LD_LIBRARY_PATH ANY_NAME
设置PATH环境变量(可执行程序的查找路径):
export PATH=$PATH:/xlwang
设置LD_LIBRARY_PATH环境变量(动态库的查找路径):
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xlwang
*设置XLWANG环境变量:
`export XLWANG=$XLWANG:/555
*运行上述程序的可执行文件,得到下列结果。由下图所示,以上三个被定义的环境变量全部被包括在shell中。
任务六:PATH环境变量和Set-UID程序
- 实验过程一:以下Set-UID程序应该执行/bin/ls命令。但是,程序员只能使用ls命令的相对路径,而不是绝对路径:
int main()
{
system("ls");
return 0;
}
编译上述程序,并将其所有者改为root,将其设置为Set-UID程序。你可以让这个Set-UID程序运行你的代码而不是/bin/ls吗?描述和解释你的观察。
- 实验过程二:将上述代码段补齐,并命名为task6.c,用GCC对其进行编译,将其编译后的可执行文件权限改为root权限。运行task6,发现该程序执行的是ls命令。由于system()函数是调用了shell环境变量,运行task5,发现SHELL=/bin/bash。于是将自己的可执行文件夹所在的目录加在了SHELL环境变量的开头:
`export SHELL=/xlwang/3:$SHELL
又将task6.c中的system()函数的参数改为task5,即想让该程序执行task5程序。
运行./task6。在终端中输出了所有的环境变量。
任务七:LD_PRELOAD环境变量和Set-UID程序
- 实验过程一:我们新建一个动态链接库。命名下面的代码为mylib.c,该程序基本上覆盖了libc中的sleep函数:
#include <stdio.h>
void sleep (int s)
{
/* If this is invoked by a privileged program,
you can do damages here! */
printf("I am not sleeping!\n");
}
用下列命令编译mylib.c:
gcc -fPIC -g -c mylib.c #fPIC表示编译生成代码与位置无关
gcc -shared -o libmylib.so.1.0.1 mylib.o -lc #让编译器知道是要编译一个共享库
设置LD_PRELOAD环境变量:
export LD_PRELOAD=./libmylib.so.1.0.1
编译myprog程序,在链接库libmylib.so.1.0.1的相同目录下:
/* myprog.c */
int main()
{
sleep(1);
return 0;
}
在以下情况中运行myprog程序:
以普通用户的身份运行myprog程序。
以普通用户运行拥有root权限的myprog程序。
使myprog成为一个Set-UID user1程序,在user2用户(非root用户)中再次设置LD_PRELOAD环境变量,运行myprog程序。
执行结果:
以普通用户的身份运行myprog程序时,输出:I am not sleeping!
以普通用户运行拥有root权限的myprog程序时,无输出。
在user2用户中再次设置LD_PRELOAD环境变量并运行myprog程序时,输出:I am not sleeping!
观察以上三次程序的执行结果,理解导致他们不同的原因。环境变量起了作用。设计实验证明主要因素,并解释第二步中行为的不同。
导致他们不同的原因就在于LD_PRELOAD环境变量。LD_PRELOAD环境变量是Unix动态链接库的世界中的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。这个功能主要是用来有选择性的载入不同动态链接库中的相同函数。在该实验中,mylib.c通过sleep函数,生成了一个libmylib.so.1.0.1链接库。然后将该链接库添加到LD_PRELOAD环境变量上。比较这三次实验,第一次和第三次实验myprog程序均具有seed用户权限,而在seed用户的LD_PRELOAD环境变量中也添加了该链接库。因此,这两个实验
任务八:使用system()和execve()调用外部程序
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *v[3];
char *command;
if(argc < 2) {
printf("Please type a file name.\n");
return 1;
}
v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = NULL;
command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
sprintf(command, "%s %s", v[0], v[1]);
// Use only one of the followings.
system(command);
// execve(v[0], v, NULL);
return 0 ;
}
- 实验过程一:编译上面的程序,赋予其root用户权限,并将其变为SET-UID程序:
该程序将会使用system()来调用命令。若将上述代码中的
v[0] = "/bin/cat"
改为v[0] = "rm"
,即删除命令。并新建一个test.c文件,将其权限改为000,执行以下命令:
./task8 ./test.c
可发现test.c文件被删除。整个过程如下图所示。
本来test.c对seed用户是不可写的,但因为task8是SET-UID程序,且时root权限,因此可以删除test.c文件。由此可得出结论:set-UID程序是非常危险的。
- 实验过程二:注释掉system(command)语句,并取消注释execve()语句;程序将使用execve()来调用命令。编译程序,并使其成为Set-UID程序。那么在步骤一中的攻击是否仍然有效?
任务九:权能泄露
- 实验过程:编译以下程序,将其所有者更改为root,并将其设置为Set-UID程序。以普通用户身份运行程序,并描述您所观察到的内容。文件/etc/zzz是否被修改?
请解释你的观察过程。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
void main()
{ int fd;
/* Assume that /etc/zzz is an important system file,
* and it is owned by root with permission 0644.
* Before running this program, you should creat
* the file /etc/zzz first. */
fd = open("/etc/zzz", O_RDWR | O_APPEND);
if (fd == -1) {
printf("Cannot open /etc/zzz\n");
exit(0);
}
/* Simulate the tasks conducted by the program */
sleep(1);
/* After the task, the root privileges are no longer needed,
it's time to relinquish the root privileges permanently. */
setuid(getuid()); /* getuid() returns the real uid */
if (fork()) { /* In the parent process */
close (fd);
exit(0);
} else { /* in the child process */
/* Now, assume that the child process is compromised, malicious
attackers have injected the following statements
into this process */
write (fd, "Malicious Data\n", 15);
close (fd);
}
}
Reference
http://blog.sina.com.cn/s/blog_8043547601017qk0.html
http://blog.csdn.net/haoel/article/details/1602108
SEED实验——Environment Variable and Set-UID Program实验报告的更多相关文章
- SEED实验——Environment Variable and Set-UID Program实验描述与实验任务
第一部分:实验描述 该实验的学习任务是理解环境变量是如何影响程序和系统行为的.环境变量是一组动态命名的变量 第二部分:实验任务 2.1 任务一:操作环境变量 在这个任务中,我们研究可以用来设置和取消设 ...
- JRE_HOME environment variable is not defined correctly This environment variableis needed to run this program
已经安装了JDK1.7 和对应JRE 安装了tomcat8 都是解压版 并设置了JAVA_HOME.JRE_HOME 但Tomcat在启动过程中找不到 错误: the JRE_HOME environ ...
- 普通用户操作tomcat项目时报:Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program
在使用普通用户更新tomcat项目适合出现这个信息,Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At ...
- TOMCAT-报错The BASEDIR environment variable is not defined correctly
<span style="font-size:18px;">The BASEDIR environment variable is not defined correc ...
- [转]Tomcat----Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
对于使用IDE开发的程序员来讲,并不是所有人都对自己用来吃饭的工具了如指掌.常在阴沟跑,哪能不翻船.为此我把自己使用Tomcat/Eclipse的一些经验教训整理了一下,会陆续的贴出来,也许会帮到和我 ...
- tomcat启动报错:Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable
linux 下 启动tomcat 报: Neither the JAVA_HOME nor the JRE_HOME environment variable is definedAt least o ...
- 【TOMCAT启动异常】The BASEDIR environment variable is not defined correctly
<span style="font-size:18px;">The BASEDIR environment variable is not defined correc ...
- linux安装tomcat Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
这两天我们的开发机重启了好几次,发现每次重启后我的tomcat总是没有启动.检查java路径,配置正确,后来拿普通账号启动tomcat时报如下的错: Neither the JAVA_HOME nor ...
- [Tomcat]The JRE_HOME environment variable is not defined correctly
在tomcat的bin目录下,双击startup.bat,闪一下,就没了,后来仔细看了一下黑屏闪的内容如下: the JRE_HOME environment variable is not defi ...
随机推荐
- Debug Dump file
dump file is a snapshot of the processs memeory. to debug it, we need use its corresponding executiv ...
- linux查找删除某天前的文件(转载)
语句写法:find 对应目录 -mtime +天数 -name "文件名" -exec rm -rf {} \; 例1: 将/usr/local/backups目录下所有10天前带 ...
- vs/windows程序找不到入口点cuvidGetDecodeStatus于AppDecGL.exe动态链接库上
解决方法:这个问题的原因是由于使用的英伟达显卡驱动版本不够新,更新显卡驱动即可. 找了一个多月的原因,终于知道起源了.最终问题还是出在了nvcuvid.lib/.dll上面.通过分析vs调试信息可以得 ...
- django中常用的数据查询方法
https://blog.csdn.net/chen1042246612/article/details/84071006
- python3学习笔记之十七
1. 网站本质:通过socket建立连接. 服务端(网站) 1. 先启动并监听:80端口 4. 获取请求信息 请求头 请求体 5. 处理请求 响应内容: 响应头:\r\n\r\n响应体 ...
- Django学习(一)
Django 是python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站.(emmmm,百度百科).本学期需要做python数据的可视化,之前搞过两次SMM和SSH,但是之后ja ...
- python爬虫之如何随机更换User-Agent
python爬虫爬取网站内容时,如果什么也没带,即不带报头headers,往往会被网站管理维护人员认定为机器爬虫.因为,此时python默认的user-agent如Python-urllib/2.1一 ...
- Angular changeDetction
ChangeDection 检测程序内部状态,然后反映到UI上. 引起状态变化:Events,XHR,Timers ApplicationRef监听NgZone的onTurnDone,然后执行检测. ...
- Excel 统计区间频数,按照条件标记
MS Office 2013 统计区间频数--countif函数 如要统计[75,90)区间段的成绩,使用 =COUNTIF(L3:L44, ">=75")-COUN ...
- RabbitMQ 保证消息不丢失
参考:https://www.imooc.com/article/49814 发送消息的时候,加上messageId字段,数据库记录消息日志表 ,插入的时候为发送中 当收到消息的时候,更改为已发送 , ...