文档章节

Linux下文件设置用户编码setuid详解

COSE
 COSE
发布于 2016/01/29 17:50
字数 2078
阅读 78
收藏 4
点赞 1
评论 0

    我们知道,Linux每个文件的详细属性都存储在一个stat结构中,可以用stat命令查看文件的详细属性,例如文件大小,修改时间,所属用户,文件权限等。

struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode;    /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;     /* user ID of owner */
    gid_t     st_gid;     /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* time of last access */
    time_t    st_mtime;   /* time of last modification */
    time_t    st_ctime;   /* time of last status change */
};


在stat结构中,st_mode字段表示了文件的模式相关属性。下图是关于该字段的详细描述,可以发现st_mode通过一个8进制数字存储文件模式:

  • 后三位分布表示了文件读、写、执行的权限以及文件的掩码mask信息
  • 第4位表示文件的粘着位,设置用户组编号,设置用户编号信息
  • 其他位表示了文件的类型信息(管道,设备,文件夹,普通文件等)
S_IFMT     0170000   bit mask for the file type bit fields
S_IFSOCK   0140000   socket
S_IFLNK    0120000   symbolic link
S_IFREG    0100000   regular file
S_IFBLK    0060000   block device
S_IFDIR    0040000   directory
S_IFCHR    0020000   character device
S_IFIFO    0010000   FIFO
S_ISUID    0004000   set-user-ID bit
S_ISGID    0002000   set-group-ID bit (see below)
S_ISVTX    0001000   sticky bit (see below)
S_IRWXU      00700   mask for file owner permissions
S_IRUSR      00400   owner has read permission
S_IWUSR      00200   owner has write permission
S_IXUSR      00100   owner has execute permission
S_IRWXG      00070   mask for group permissions
S_IRGRP      00040   group has read permission
S_IWGRP      00020   group has write permission
S_IXGRP      00010   group has execute permission
S_IRWXO      00007   mask for permissions for others (not in group)
S_IROTH      00004   others have read permission
S_IWOTH      00002   others have write permission
S_IXOTH      00001   others have execute permission


下面一段代码将对setuid的使用作出简单说明。父进程通过fork创建一个子进程,然后父进程和子进程将分别打印设置用户ID,最后父进程将会尝试创建一个新的文件。

#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    int fd;
    pid_t pid;

    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork error\n");
        exit(1);
    } else if (pid == 0) {
        printf("child real user id: %d\n", getuid());
        printf("child effective user id: %d\n", geteuid());
    } else {
        sleep(1);
        printf("parrent real user id: %d\n", getuid());
        printf("parrent effective user id: %d\n", geteuid());
        exit(0);
    }
    if ((fd = open(argv[1], O_CREAT | O_RDWR)) < 0) {
        fprintf(stderr, "open error\n");
        fprintf(stderr, "error: %s\n", strerror(errno));
    }

    close(fd);

    return 0;
}

编译并执行程序,结果如下:

roo@roose:~$ ls -l a.out
-rwxrwxr-x 1 roo roo 9174 Jan 29 17:17 a.out*
roo@roose:~$ ./a.out /usr/local/testfile
child real user id: 1000
child effective user id: 1000
parrent real user id: 1000
parrent effective user id: 1000
open error
error: Permission denied

根据打印的信息,可以发现

  • 父进程和子进程的实际用户ID和有效用户ID都是1000,即为普通用户
  • 尝试创建文件/usr/local/testfile时,程序提示权限错误,说明执行用户权限为普通用户


下面修改a.out的属性,设置文件拥有者为root用户,添加setuid

roo@roose:$ sudo chown root:root a.out
roo@roose:$ sudo chmod 4775 a.out
roo@roose:$ ls -l a.out
-rwsrwxr-x 1 root root 9174 Jan 29 17:17 a.out

然后重新执行程序

roo@roose:~$ ./a.out /usr/local/testfile
child real user id: 1000
child effective user id: 0
parrent real user id: 1000
parrent effective user id: 0

根据打印的信息,可以发现:

  • 进程的实际用户编号(uid)为执行用户的用户编号1000,即为普通用户
  • 进程的有效用户编号(euid)是文件所属用户的用户编号0,即为root用户
  • 子进程也集成了父进程的实际用户编号和有效用户编号
  • 父进程成功创建了/usr/local/testfile文件,说明程序是以root权限执行的

尝试执行设置了setuid的shell脚本,创建脚本文件test.sh内容如下:

#!/bin/bash
sleep 10
touch /usr/local/testfile
roo@roose:~$ sudo chown root:root test.sh
roo@roose:~$ sudo chmod 4775 test.sh
roo@roose:~$ ./test.sh &
[1] 54280
roo@roose:~$ ps -eo uid,euid,command | grep test.sh
 1000  1000 /bin/bash ./test.sh
 1000  1000 grep --color=auto test.sh
roo@roose:~$ touch: cannot touch ‘/usr/local/testfile’: Permission denied

同样对test.sh赋予相关权限并执行,结果却和上面C生成的可执行文件不太一样:

  • 程序的实际用户编号(uid)和有效用户编号(euid)都是1000,即为普通用户;
  • 程序也没有权限创建/usr/local/testfile,即添加的设置用户编号没有效果。

为什么已经设置了setuid却没有效果呢?通过查找相关资料,发现出现该问题的原因是:

    出于安全问题,Linux会忽略任何编译器文件的设置用户位。

详细说明如下(博主太懒,有空再翻译)

http://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts

Linux ignores the setuid¹ bit on all interpreted executables (i.e. executables starting with a #! line). The comp.unix.questions FAQ explains the security problems with setuid shell scripts. These problems are of two kinds: shebang-related and shell-related; I go into more details below.

If you don't care about security and want to allow setuid scripts, under Linux, you'll need to patch the kernel. As of 3.x kernels, I think you need to add a call to install_exec_creds in the load_script function, before the call to open_exec, but I haven't tested.
Setuid shebang

There is a race condition inherent to the way shebang (#!) is typically implemented:
    The kernel opens the executable, and finds that it starts with #!.
    The kernel closes the executable and opens the interpreter instead.
    The kernel inserts the path to the script to the argument list (as argv[1]), and executes the interpreter.

If setuid scripts are allowed with this implementation, an attacker can invoke an arbitrary script by creating a symbolic link to an existing setuid script, executing it, and arranging to change the link after the kernel has performed step 1 and before the interpreter gets around to opening its first argument. For this reason, most unices ignore the setuid bit when they detect a shebang.

One way to secure this implementation would be for the kernel to lock the script file until the interpreter has opened it (note that this must prevent not only unlinking or overwriting the file, but also renaming any directory in the path). But unix systems tend to shy away from mandatory locks, and symbolic links would make a correct lock feature especially difficult and invasive. I don't think anyone does it this way.

A few unix systems (mainly OpenBSD, NetBSD and Mac OS X, all of which require a kernel setting to be enabled) implement secure setuid shebang using an additional feature: the path /dev/fd/N refers to the file already opened on file descriptor N (so opening /dev/fd/N is roughly equivalent to dup(N)). Many unix systems (including Linux) have /dev/fd but not setuid scripts.

    The kernel opens the executable, and finds that it starts with #!. Let's say the file descriptor for the executable is 3.
    The kernel opens the interpreter.
    The kernel inserts /dev/fd/3 the argument list (as argv[1]), and executes the interpreter.

Sven Mascheck's shebang page has a lot of information on shebang across unices, including setuid support.


Setuid interpreters

Let's assume you've managed to make your program run as root, either because your OS supports setuid shebang or because you've used a native binary wrapper (such as sudo). Have you opened a security hole? Maybe. The issue here is not about interpreted vs compiled programs. The issue is whether your runtime system behaves safely if executed with privileges.

    Any dynamically linked native binary executable is in a way interpreted by the dynamic loader (e.g. /lib/ld.so), which loads the dynamic libraries required by the program. On many unices, you can configure the search path for dynamic libraries through the environment (LD_LIBRARY_PATH is a common name for the environment variable), and even load additional libraries into all executed binaries (LD_PRELOAD). The invoker of the program can execute arbitrary code in that program's context by placing a specially-crafted libc.so in $LD_LIBRARY_PATH (amongst other tactics). All sane systems ignore the LD_* variables in setuid executables.

    In shells such as sh, csh and derivatives, environment variables automatically become shell parameters. Through parameters such as PATH, IFS, and many more, the invoker of the script has many opportunities to execute arbitrary code in the shell scripts's context. Some shells set these variables to sane defaults if they detect that the script has been invoked with privileges, but I don't know that there is any particular implementation that I would trust.

    Most runtime environments (whether native, bytecode or interpreted) have similar features. Few take special precautions in setuid executables, though the ones that run native code often don't do anything fancier than dynamic linking (which does take precautions).

    Perl is a notable exception. It explicitly supports setuid scripts in a secure way. In fact, your script can run setuid even if your OS ignored the setuid bit on scripts. This is because perl ships with a setuid root helper that performs the necessary checks and reinvokes the interpreter on the desired scripts with the desired privileges. This is explained in the perlsec manual. It used to be that setuid perl scripts needed #!/usr/bin/suidperl -wT instead of #!/usr/bin/perl -wT, but on most modern systems, #!/usr/bin/perl -wT is sufficient.

Note that using a native binary wrapper does nothing in itself to prevent these problems. In fact, it can make the situation worse, because it might prevent your runtime environment from detecting that it is invoked with privileges and bypassing its runtime configurability.

A native binary wrapper can make a shell script safe if the wrapper sanitizes the environment. The script must take care not to make too many assumptions (e.g. about the current directory) but this goes. You can use sudo for this provided that it's set up to sanitize the environment. Blacklisting variables is error-prone, so always whitelist. With sudo, make sure that the env_reset option is turned on, that setenv is off, and that env_file and env_keep only contain innocuous variables.

TL,DR:

    Setuid shebang is insecure but usually ignored.
    If you run a program with privileges (either through sudo or setuid), write native code or perl, or start the program with a wrapper that sanitizes the environment (such as sudo with the env_reset option).

© 著作权归作者所有

共有 人打赏支持
COSE

COSE

粉丝 6
博文 22
码字总数 10162
作品 0
南京
程序员
Linux权限管理详解

Linux权限管理详解 1、Linux 的基本权限: (1)Linux的基本权限说明 -rw-r--r-- 1 root root 08-11 01:45 aa.txt 权限位是十位 第一位:代表文件类型 - 普通文件 d 目录文件 l 链接文件 b ...

long9617 ⋅ 2017/12/02 ⋅ 0

linux系统权限大全

linux系统权限大全 一、 文件的归属: 文件所有者(owner)、用户组(group)、其它人(others) 二、查看 linux文件权限以及归属ls 命令 ls -al 查看文件详细权限和属性 权限 r w x 三、设置...

lzp5896 ⋅ 2017/07/21 ⋅ 0

setuid和setgid位详述

setuid和setgid位详述 分类: UNIX/LINUX 学习心得 2009-04-01 18:56136人阅读评论(0)收藏举报 setuid和setgid位 [1] setuid位 如果在可执行文件上设置了setuid位,运行可执行文件的进程将拥...

linhao_214 ⋅ 2011/07/23 ⋅ 0

Linux命令find -perm使用方法

花了点时间才将linux中find命令的-perm参数弄懂,分享一下。 find -perm,根据文件的权限来查找文件,有三种形式: find -perm mode find -perm -mode find -perm +mode 那么这三者之间有什么...

yolks丶 ⋅ 2016/10/09 ⋅ 0

Linux运维工程师笔试题系列6(30题)

Linux运维工程师笔试题系列6(30题) 如果您对问题有疑问,或者认为答案不准确的,欢迎留言交流。 问题如下: 1. cat -n file1file2 命令的意思是? A 只会把文件file1的内容输出到屏幕上。 ...

优惠码发放 ⋅ 今天 ⋅ 0

linux set uid ,set gid,sticky bit权限详细说明

一个文件都有一个所有者, 表示该文件是谁创建的. 同时, 该文件还有一个组编号, 表示该文件所属的组, 一般为文件所有者所属的组. 如果是一个可执行文件, 那么在执行时, 一般该文件只拥有调用该...

yolks丶 ⋅ 2016/10/09 ⋅ 0

linux之权限之强制位和冒险位

linux文件权限之文件的强制位、冒险位 上篇跟大家分享了linux的ugo权限,今天跟大家扩展一下,大家在工作中一定有些困惑比如说是否可以让普通用户可以临时以root用户的权限去执行?是否可以让一...

higesky ⋅ 2017/03/19 ⋅ 0

Linux命令find -perm使用方法

花了点时间才将linux中find命令的-perm参数弄懂,分享一下。 find -perm,根据文件的权限来查找文件,有三种形式: find -perm mode find -perm -mode find -perm +mode 那么这三者之间有什么...

长平狐 ⋅ 2012/11/01 ⋅ 0

Linux权限管理

权限管理是Linux中一个十分重要的概念,也是系统安全性的重要保障。 一、基本权限 用户对文件拥有所有者,所属组和其他人三个身份,每个身份都有读写执行三个权限。 -rw-r--r--:第一个"-"位置...

wt7315 ⋅ 2016/09/08 ⋅ 0

[Android] adb setuid提权漏洞的分析

原来我看到一篇关于分析RageAgainstTheCage源码的很不错的文章,后来发现原链接失效了,只能从网页的缓存副本中找寻蛛丝马迹。下面就是我找到的内容,保存到自己的博客中,来保证以后能找到。...

亭子happy ⋅ 2012/09/12 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

解决yum安装报错Protected multilib versions

使用yum安装报错Protected multilib versions原因是因为多个库不能共存,不过更新的话也并不行,但是可以在安装命令后面加上如下一段命令: --setopt=protected_multilib=false 案例: 比如需...

北岩 ⋅ 27分钟前 ⋅ 0

为什么要学习Typescript???

简单来说 目前的typescript就是未来的javascript 为什么?? 这要从ECMA-262标准的第4版说起 对了 我们说的ES5 其实是ECMAScript3.1这个替代性建议被扶正了而已... 那么 第4版标准是什么? 看看...

hang1989 ⋅ 31分钟前 ⋅ 0

linux安装ipfs

一、下载ipfs # cd /usr/local/ipfs/ # wget https://dist.ipfs.io/go-ipfs/v0.4.15/go-ipfs_v0.4.15_linux-amd64.tar.gz # tar -zxvf go-ipfs_v0.4.15_linux-amd64.tar.gz 二、安装ipfs # ......

八戒八戒八戒 ⋅ 37分钟前 ⋅ 0

jvm程序执行慢诊断手册

生产环境最多的几种事故之一就是程序执行慢,如果是web服务的话,表现就是响应时间长。本文分享,从业多年形成的排查守则。 诊断步骤 系统资源查看 首先是系统资源查看,而且必须是在第一步。...

xpbob ⋅ 37分钟前 ⋅ 0

YII2 advanced 高级版本项目搭建-添加API应用以及多应用

一、YII安裝 安裝yii可以用composer安裝,也可以在yii中文社区下载归档文件安装 composer安装就不介绍了,因为要安装composer,比较麻烦,当然安装了composer是最好的,以后安装yii的插件要用...

botkenni ⋅ 38分钟前 ⋅ 0

在jdk1.8的环境下模拟永久代内存溢出

相信不少小伙伴在看深入理解Java虚拟机的时候,作者给我们举例一个demo来发生PermGen space 1、通过List不断添加String.intern(); 2、通过设置对应的-XX:PermSize与-XX:MaxPermSize(更快看到...

虾几把写 ⋅ 今天 ⋅ 0

开发OpenDaylight组件的完整流程

在前面介绍学习了OpenDaylight的几个重要模块后,这里再来介绍下完整开发一个模块的过程。 OSGI的bundles提供被其他OSGI组件调用的服务。这个教程中展示的是Data Packet Service去解析数据包...

wangxuwei ⋅ 今天 ⋅ 0

Java序列化和反序列化

1、什么是序列化和反序列化 序列化:把对象转换为字节序列的过程。 反序列化:把字节序列恢复成对象的过程。 2、被序列化的类需要实现serializable接口,只是为了标注该对象是可以被序列化的...

IT-Mamba ⋅ 今天 ⋅ 0

流式构建原理

流式构建需要达到分钟级的数据更新频率,Kylin采用类似于Spark Streaming的做法,每隔数分钟进行一次微构建。这边的构建需要考虑到一个延迟因素,分布式网络存在延迟等因素,该时间段的数据有...

无精疯 ⋅ 今天 ⋅ 0

在maven项目工程编写solr代码,需要的依赖

solrJ <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>6.6.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents<......

爱运动的小乌龟 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部