【SEED LAB】Set-UID privileged programs Labs - Set-UID漏洞和权限泄露

背景知识

Linux模式

用户User:文件的所有者
群Group:文件组的成员
其他Other: 不属于任何用户或组的用户
关于对文件权限分为三种,分别用三个字母来表示。分别是r(read), w(write), x(execute)。
例如drwxrwxrwx,d代表文件。三个rwx的意思是,用户,群,其他都拥有读写编辑的权限。

影子文件

在Linux中,系统使用/etc/shadow文件来保存用户的密码。通过查看/etc/shadow的访问权限可以知道,文件属于root用户,-rw-r-----代表只有root有读写的权利。
在这里插入图片描述
那么普通用户怎么修改自己的密码呢?

UID是什么

Linux中所有的进程都拥有两个ID,
Real UID(RUID):哪个用户运行了这个程序或文件,换句话说是进程的真正拥有者。
Effective UID(EUID):操作系统识别一个进程的权限。
当程序被正常执行时RUID = EUID,此时都是所有者的ID。当Set-UID执行时RUID != EUID。RUID仍然是用户ID,但是EUID时程序所有者的ID。如果程序被root拥有,那么用户就可以以root权限运行程序。

关于Set-UID的例子

首先复制cat文件,新建一个mycat文件用于观察。第二步,将mycat文件的所属权变成root。用 ls -l 命令确认一下mycat的权限。最后,在普通用户下运行程序,和预想的一样这里没有足够权限来打开影子文件。
在这里插入图片描述

我们修改一下mycat文件的特权,4755是指用户执行文件时可以有拥有者的权限。改变权限之后再一次执行可以发现,程序可以正常使用并打印了影子文件的信息。
在这里插入图片描述

最后将mycat所有者改为seed,此时文件不拥有root权限所以也无法打印影子文件的内容。
在这里插入图片描述

Set-UID的弱点

system函数

按照资料编写下面这个catcall的程序,能力一是拥有cat的技能,能力二是可以运行并读取输入的命令。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char *argv[]){
        char *cat = "/bin/cat";

        if(argc < 2){
                printf("Please type a file name.\n");
                return 1;
        }

        char *command = malloc(strlen(cat) + strlen(argv[1]) + 2);
        sprintf(command, "%s %s", cat, argv[1]);
        system(command);
        return 0;
}

编译并且给予权限后运行。方框这里出现了一点问题,原本是可以输出内容的,但是不知道是什么原因在我虚拟机上没办法实现能力一。这里直接尝试第二个能力,向两个%s中分别放入aa和/bin/sh字符。画面出现箭头所指情况,输入id后发现正常的输出,这说明我们成功的利用set uid的漏洞拿到了shell。
在这里插入图片描述

execve函数

重新用execve函数代替system函数写一个程序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char* argv[]){
        char *v[3];

        if(argc < 2){
                printf("Please type a file name.\n");
                return 1;
        }

        v[0] = "/bin/sh";
        v[1] = argv[1];
        v[2] = 0;
        execve(v[0], v, 0);

        return 0;
}

还是以相同的方式编译以及运行程序,这里发现程序成功运行。再用同样的方式试试看能不能拿到shell。
在这里插入图片描述

可以发现execve函数不像system函数一样会将数据当作代码运行。
在这里插入图片描述
补充
system()和execve()函数的区别是system函数是调用shell直接调用命令,相当于直接在命令行中输入命令。并且是两个进程同时进行,在一条进程结束后会返回下一条进程。但是execve函数不同,使用execve调用的进程会覆盖进程导致无法返回原进程。

权限泄露

某些情况,特权程序在执行过程中会自我降级。例如,有一个Set-UID特权的su程序允许切换用户。当程序运行时EUID是root,RUID是user1,验证过密码之后EUID和RUID通过自我降级变成为user2。但是因为程序在自我降级的时候可能没有清理特权,所以有权限泄露的情况存在。

练习

Task 1: Invoking External Programs Using system() versus execve()

STEP1

再练习之前将/bin/sh 和 /bin/zsh相连接
$ sudo ln -sf /bin/zsh /bin/sh

练习之后记得改回来
$ sudo ln -sf /bin/dash /bin/sh

STEP2
编译并直接运行程序,目标是以普通用户seed的权限利用程序漏洞获得shell。直接运行程序打印影子文件,发现权限不够无法打印。
在这里插入图片描述

再一次利用system的漏洞,输入/bin/sh可以看见在终端上打印了程序的代码,接着往下看
在这里插入图片描述

攻击成功,获得了shell。
在这里插入图片描述

优点

system函数可以直接调用shell,无法分离数据和命令易被攻击。execve函数可以做到分离数据和命令,因此安全性高于 system函数。
重点在于分开代码和数据!

Task 2: Capability Leak

root用户状态下在/etc下建立zzz文件输入“This is import file!”。用ls -l可以查看各用户对于文件的权限,可以知道只有root权限下有对程序进行读写的能力。其他权限只有读的权限。
在这里插入图片描述
将下面代码编辑成task2.c文件

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

void main()
{
		int fd;

		fd = open("/etc/zzz", O_RDWR | O_APPEND); /* 打开zzz文件 */
		if(fd == -1){  /* 打开失败的情况 */
				printf("Cannot open /etc/zzz file. \n ");
				exit(0);
		}

		sleep(1);  /* 暂停程序一秒 */

		setuid(getuid()); /* getuid()返回RUID */
		if(fork()){
			close(fd);
			exit(0);
		}else{
			write(fd, "Malicious Data\n", 15);
			close(fd);
}

编译之后,将程序设置成Set-UID 之后运行,可以观察到程序因为sleep(1)暂停了一秒。
在这里插入图片描述

程序执行结束后重新查看zzz文件的内容,发现内容被修改了。
在这里插入图片描述

分析

看一下task2程序,程序先利用setuid命令将程序降级之后尝试对文件进行修改。正常情况下zzz文件只有root权限才能读写,这里已经没有root权限的task2程序是不可以修改的。这里就是出现了权限泄露的问题,才让程序能够继续修改zzz文件。尽管取消了root权限,但是系统还没有收回特权导致程序可以修改原本不能操作的文件。
知道弱点之后我们可以修改代码来防止权限泄露,修改的方式也很简单。先对程序进行降级,再打开文件就可以规避问题。

修改代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

void main()
{
		int fd;
		setuid(getuid()); /* getuid()返回RUID 换到前面 */
		
		fd = open("/etc/zzz", O_RDWR | O_APPEND); /* 打开zzz文件 */
		if(fd == -1){  /* 打开失败的情况 */
				printf("Cannot open /etc/zzz file. \n ");
				exit(0);
		}

		sleep(1);  /* 暂停程序一秒 */
		
		if(fork()){
			close(fd);
			exit(0);
		}else{
			write(fd, "Malicious Data\n", 15);
			close(fd);
}

重新编译之后运行,这时候程序已经没有权限对zzz文件进行修改了。
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值