2023年12月17日发(作者:)

实验一

Linux系统文件和目录权限设置与辨识setuid程序uid差异

1、 设计并实现不同用户对不同类文件的r、w、x权限:

1) 查看/etc/passwd文件和/usr/bin/passwd文件的权限设置;

/user/bin/passwd是一个命令,可以为用户添加、更改密码,但是,用户的密码并不保存在/etc/passwd当中,而是保存在了/etc/shadow当中。所以它有执行权限,而且所有者执行时会提升到root权限(有setuid位)。

/etc/passwd是一个文件,主要是保存用户信息,例如:用户名、宿主目录、登陆环境、失效时间,但是就像上面所说的,这个文件里不保存密码。只是简单的可读文件,所有者拥有写权限。

2) 用户A具有文本文件流星雨.txt,该用户允许别人下载;

下载命令为wget,这里我将服务器里的图片文件(文件无所谓)设置权限并下载,先设置其他人只读,发现下载成功,和预期的一致,也就是说,文件只需要具有其他人读权限,即可被下载。

3) 用户A有编译了一个可执行文件,该用户想在系统启动时运行;

启动时运行服务,想到三种方法:

1. 软链接 2. chkconfig 3. ntsysv

题目说是用户自定义可执行文件,所以方法选用软链接。

随便生成一个可执行文件(直接gcc)

将生成的hjj可执行文件放到/etc/init.d中,在/etc/rc.d/rc3.d中建立软链接。

由于hjj文件在init.d中,所以需要root权限,而且需要有执行权限。

4) 用户A有起草了文件,想让同组的用户帮其修改文件;

该用户分别如何设置权限,并验证其设置的正确与否

rw-rw-r—

创建此类文件,然后新建用户xyy, hjj,组为lovebear

查看属于lovebear组的用户,有hjj和xyy

切换到xyy用户,修改hjj.c文件

修改成功!

2、 设计并实现setuid程序的使用,并分析不同用户fork调用setuid程序后euid、ruid、suid的差别,以及用户调用execl执行setuid程序后euid、ruid、suid的差别。

(1)实验原理:

1. 三个uid的区别

Ruid: 用于在系统中标识一个用户是谁,当用户使用用户名和密码成功登录后一个UNIX系统后就唯一确定了他的Ruid.

Euid: 用于系统决定用户对系统资源的访问权限,通常情况下等于Ruid,在设置suid位后,会有权限的改变,将不等于Ruid。

Suid: 用于对外权限的开放。跟Ruid及Euid是用一个用户绑定不同,它是跟文件而不是跟用户绑定。

2. setuid函数解析

库文件:

#include

#include

函数声明:

Int setuid(uid_t uid);

返回值:

成功返回1,失败返回-1

函数功能:

a. 若进程具有root权限,可将ruid,euid,suid设置为uid

b. 若进程为普通用户,但是uid等于ruid或suid,setuid只将euid设置为uid,而ruid和suid不变。

c.

若上面都不满足,则返回错误。

(2)实验过程

分别以Root和lovebear(普通用户)运行test_f_e程序,test_f_e中分别fork子进程运行和execl运行一系列setuid。

其中setuid测试函数设计为

目的

验证a情况root可以设置三个uid

验证c情况

验证b情况

验证普通用户无法提权

为下一步再次充分验证b情况铺垫

充分验证b情况

函数

Setuid(1000)

Setuid(1002)

Setuid(1000)

Setuid(0)

Setresuid(1001,1000,0)

Setuid(0)

(3)实验结果

运行结果中有execl执行的setuid结果,fork子进程的setuid结果验证,在每一块开头记录了当前运行的ruid, euid, suid的当前值。

Lovebear身份运行:

Root身份运行:

(4)实验结果分析

可以看到,fork()和execl中的setuid执行效果是一样的,所以直接讲setuid后的结果。

可以看出fork后的子进程和execl运行程序后的ruid, euid, suid的值都完全继承了父进程的id,但execl运行后,将不会在执行后面的代码(所以将它放在代码最后)。我的运行程序exec1是root的,但是通过exec1返回的euid可知,他继承了父进程的uid。

Lovebear身份运行时

1. setuid(1000), 因为3个uid的初始就是1000(因为lovebear的uid为1000)

2. setuid(1002), 没有成功,返回error,情况a,普通用户不能随意设置uid(不满足情况b的条件下)。

3. setuid(1000), uid等于ruid,euid被设置为uid,这里验证不明显,因为初始就是1000,后面有更明显的例子。

4. setuid(0), 返回error,低权限的lovebear用户无法升级为root权限,也验证了a情况。

5. setresuid(1001,1000,0), setuid(0), 返回error,同4。

Root身份运行时

1. setuid(1000), 验证了a情况,可以任意设置uid

2. setuid(1002), 此时eui已经是1000了,无法再任意改uid。

3. setresuid(1001,1000,0), setuid(0), 这里uid等于suid,满足b情况,只将euid改为uid—0,而ruid,suid保持不变。

(5)实验体会

这次实验刚开始一看,觉得很简单,可是,在实际操作起来并没有想象中的那么容易。前面的题目一相对来讲容易许多,只需要进行一些简单的修改文件权限来找到结果,可以说是热身题。

第二题就需要自己去设计方法去验证一系列的结论,查找了许多的资料,在ubuntu下反复尝试,虽然很复杂,但是感觉很有趣,我觉得这个实验很有意义,使我更深入的研究了ruid, euid, suid之间的联系,区别及权限的控制。还验证了fork和execl的异同,收获颇丰。

(6)附录(源代码)

Test_f_e.c

#include

#include

#include

#include

#include

int main(){

uid_t ruid=0,euid=0,suid=0;

getresuid(&ruid,&euid,&suid);

printf("parent ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

if(fork()==0){

printf("childproc ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

if(setuid(1000)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(1002)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(1000)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(0)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

exit(0);

}else{

setresuid(1001,1000,0);

if(setuid(0)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

printf("execl function n");

execl("exec1",NULL);

}

wait(NULL);

// execl("exec1",NULL);

return 0;

}

Exec1.c

#include

#include

#include

#include

int main(){

uid_t ruid,euid,suid;

getresuid(&ruid,&euid,&suid);

printf("exec1 proc

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

if(setuid(1000)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(1002)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(1000)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

if(setuid(0)==-1){

printf("errorn");

}else{

printf("successt");

getresuid(&ruid,&euid,&suid);

printf("current

ruid:%dteuid:%dtsuid:%dn",ruid,euid,suid);

}

return 0;

}