Set-UID与环境变量

特权程序(privileged program)

任何具有附加特权的程序都可以被认为是特权程序。
特权程序有两种形式:daemonSet-UID
daemon:作为后台处理的程序,要想作为一个privileged program,需要具有特权的UID,例如root。在Windows系统中,称为services(服务),而不叫作daemon,services和daemon都是作为后台程序运行的。
Set-UID: 广泛运用在linux系统中,使用一个特殊bit标志一个程序是否是Set-UID程序。在linux系统中存在三个用户ID(user ID),

  • real user ID:登录用户的uid,例如以jack登录Linux系统,则linux运行的所有命令的real uid均为jack。
  • effective user ID:用于访问控制的ID,一般情况下euid=ruid,若设置有Set-UID bit,则euid在文件(linux一切皆文件)运行时为文件所有者的uid,而不是ruid。
  • saved user ID:

Set-UID机制的安全性依赖于一个假设:用户只能按照程序运行的操作来操作。但是这很难保证。

Capability Leaking

一些特权程序会在其执行过程中进行降权(downgrade),变成普通程序,即非特权程序,但是若在降权之前没有释放一些变量,例如文件描述符(file descripter),则存在Capalibility Leaking漏洞,参考如下程序:

/* capLeak.c*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

void main()
{
	int fd;
	char *v[2];
	fd=open("/etc/test",O_RDWR|O_APPEND);
	if(fd==-1)
	{
		printf("Cannot Open file /etc/test\n");
		exit(0);
	}
	printf("fd=%d\n",fd);
		

	setuid(getuid());

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

在该程序中,使用open函数打开了/etc/test文件(如果没有需要自己创建一个),该文件普通用户无权进行修改,该程序在运行时通过setuid()降权,但是其在降权前后没有释放其在特权状态下打开的变量fd,即文件描述符,故存在一个capability leaking,使用如下命令可以试验:

gcc -o capLeak capLeak.c
sudo chown root capLeak
sudo chmod 4755 capLeak

在这里插入图片描述
可以看到起初/etc/test文件内没有内容,运行capLeak程序后,其通过execve()函数调用/bin/sh,且在降权前后没有释放fd,故在生成的shell中,依旧可以访问该fd对应的文件。

如上述程序在setuid()前添加close(fd),再次实验可以发现
在这里插入图片描述
即在降权前已经释放了fd,没有capability leaking

Set-UID的攻击面

对于一个特权程序,它的攻击面是程序获得输入的总和;没有对输入进行处理,便有可能影响程序的行为,如下为Set-UID的攻击面:
在这里插入图片描述
其攻击面主要有四:

  • 用户输入
  • 用户可控制的系统输入:
  • 环境变量
  • 用户控制的非特权程序
环境变量

环境变量属于hidden input,许多开发者可能不能意识到这些hidden input所带来的的危害,例如PATH,若用户没有提供命令的完成路径,则shell到PATH指定的路径下查找该命令。
c程序中访问当前进程的环境变量有两种方法:(1)envp[]数组(2)environ全局变量,建议在访问环境变量时使用environ全局变量。

查看当前进程的环境变量:关于/proc文件系统,参考/proc

strings /proc/$$/environ

进程获取获取环境的方法

(1)如果是一个新进程,例如fork()系统调用生成的进程,则子进程继承了父进程的环境变量(因为fork是通过复制调用进程来创建一个子进程的)
(2)如果一个进程在其内部运行一个进程,例如使用execve()系统调用,该系统调用使用提供的数据重写当前进程的内存,因此所有的存储在该进程中的环境变量都会消失。当使用execve()系统调用时,如果一个进程想把其环境变量传递给子进程,则必须显示传递(例如exceve()的第三个参数使用environ);

execve函数原型:

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

环境变量内存分布

环境变量存储在栈中,函数的main()函数被调用前,三个数据块被压栈,如下:
在这里插入图片描述
标号①:存储环境变量字符串的地方
标号②:存储指向环境变量数组的指针数组envp
标号③:存储指向参数变量数组的指针输出argv
标号④:main()函数栈帧

修改、删除、增加环境变量可能会导致预先分配的内存空间①②不够,若出现这种情况,整个环境变量块会改变到其他位置(通常在堆中),同时,全局变量environ也需要相应的改变,以使其始终指向更新后的环境变量数组,但是main()中的第三个参数envp并不会改变,所以envp始终指向原始环境变量块。

shell变量

shell变量是由shell程序维持的内部变量,影响shell的行为。shell变量与环境变量不同,shell变量可以变成环境变量,环境变量也可以变成shell变量。当一个shell程序启动时,其为每个环境变量(键值对)作一个拷贝,作为其shell变量,但之后,二者独立存在,任何一方的改变都不会影响另一方。
shell变量影响子进程的环境变量,shell常见用法是执行程序,当我们在shell中输入一个程序名,shell会在子进程中执行该程序(通常通过fork()和execve()实现),当在新进程中执行程序时,shell会显示的为子进程设置环境变量。
以bash为例,以下两种类型的shell变量会传递给子进程。

  • 复制环境变量得到的shell变量:所有从环境变量得到的shell变量都可以被子进程继承,除了使用unset命令删除的shell变量。
  • 用户使用export自定义的shell变量

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值