前言:
博主在前不久的一个项目中,项目组的组员需要删除由daemon守护进程创建的缓存文件。但是删除这些缓存文件需要超级用户权限。博主用root用户创建了一个设置用户id的shell脚本来实现此功能。但是此脚本并没有如预期那样工作。今天就浅谈一下设置用户id位,为什么对shell脚本无效。
假设我们文件结构如下图所示
Cache文件目录下有3个缓存文件,分别为cache1、cache2、cache3,这三个文件为daemon用户所有
下面我们来看一下设置用户id位的两种工作方式。
- 对shell脚本文件设置“设置用户id位”
现在我们有一个名为"d_cache.sh"的shell脚本,脚本的功能是删除Cache文件目录中的所有缓存文件
运行脚本,显示无权操作
现在我们更改为root用户,并设置设置用户id位,并执行脚本
结果如图所见,虽然把文件所有者更改为了root,并且设置了设置用户id位,但是“然并卵”。
- 对可执行二进制文件设置“设置用户id位”
现在我们在一个名为system.c的C程序中通过execl函数,exec“d_cache.sh”脚本,然后看看会发生什么。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> int main(void) { pid_t pid; if ((pid = fork()) < 0) { printf("fork error: %s\n", strerror(errno)); exit(0); } else if (pid == 0) { /* 子进程 */ /* 将实际用户id,有效用户id,保存的设置用户id都设置为0(也就是超级用户) */ setuid(0); if (execl("/home/paul/test/d_cache.sh", "d_cache.sh", (char *)0) < 0) { printf("execl error: %s\n", strerror(errno)); exit(0); } } exit(0); }
编译system.c文件,生成可执行二进制文件a.out,运行结果如下图
把a.out的所有者更改为root,并且启用设置用户id位,然后运行结果如下图
成功的把Cache文件目录中的缓存文件删除掉了。
警告:这种实现方法存在巨大的安全隐患,在文件d_cache.sh中的任何命令都将以root权限执行。最好把d_cache.sh文件的访问权限改为755,并且文件所有者改为root所有,即普通用户不能修改此文件。
为什么会出现这种区别呢?
这就涉及与进程相关的三个用户ID(暂不讨论组ID)
- 实际用户ID(登陆ID)
- 有效用户ID(用于检查文件的权限)
- 保存设置用户ID(由exec复制有效用户ID得来)
以上面的二进制可执行文件a.out为例,我们来分析一下,程序在运行中三个用户ID的变化
进入main后,fork之前,父进程中的三个用户ID
- 实际用户ID = paul(登陆ID)
- 有效用户ID = root (由于设置了设置用户ID位,exec把有效用户ID设置为文件的所有者即root)
- 保存设置用户ID = root(exex复制有效用户ID)
在子进程中,调用setuid(0)之前。子进程继承父进程的属性,这时子进程中三个用户ID
- 实际用户ID = paul
- 有效用户ID = root
- 保存设置用户ID = root
子进程中调用setuid(0)后,子进程的三个用户ID
- 实际用户ID = root
- 有效用户ID = root
- 保存设置用户ID = root
此后,子进程中的所有操作都将具有root权限。
在子进程中execl函数定位到文件"/home/paul/test/d_cache.sh",但该文件不是一个由连接编辑器产生的机器可执行文件,于是execl就认为该文件是一个shell脚本,于是接着调用/bin/sh,并以路径"/home/paul/test/d_cache.sh"作为shell的输入。当/bin/sh是bash版本2以上时,如果有效用户ID不等于实际用户ID时,bash会把有效用户ID设置为实际用户ID。所以在sysyem.c程序子进程中,如果在execl之前没有语句setuid(0),那么后续执行的d_cache.sh脚本就不具有root权限。
由于存在巨大的安全漏洞,Linux忽略所有解释器文件(首行以#!开始)的设置用户ID位。这也就是设置用户ID位,对shell脚本无效的原因。
paul@localhost:~/test$ ls -l d_cache.sh -rwsrwxr-x 1 root root 49 Dec 27 16:09 d_cache.sh paul@localhost:~/test$ ./d_cache.sh rm: cannot remove ‘/home/paul/test/Cache/cache1’: Permission denied rm: cannot remove ‘/home/paul/test/Cache/cache2’: Permission denied rm: cannot remove ‘/home/paul/test/Cache/cache3’: Permission denied paul@localhost:~/test$
结束语:以上为本人对setuid为什么对shell脚本无效的一点浅薄认识。由于本人水平所限,如有错误,欢迎批评指正。
参考文献:
2. http://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts/2910#2910
3. http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html
4. https://en.wikipedia.org/wiki/Setuid
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关推荐
提问: 我想要知道运行中脚本子shell的进程id。我该如何在shell脚本中得到PID。 当我在执行shell脚本时,它会启动一个叫子shell的进程。作为主shell的子进程,子shell将shell脚本中的命令作为批处理运行(因此称为...
linux 批量解压文件shell脚本 教程:https://www.bilibili.com/video/BV1Zi4y1C7rL?spm_id_from=333.999.0.0
linux shell写的通讯录脚本,有增删改查,id自增长功能,
使用一般的mysql命令或者是sql脚本都可以插入数据到mysql数据表中,我这里介绍如何是Shell批量的从CSV文件中添加数据到mysql数据库中,方便数据迁徙,测试数据的添加之类的工作。
在Linux系统的/etc目录下有这样一个文件passwd,该文件里包含系统中所有用户信息的记录,记录里包含每个用户的如下信息:用户名、密码、用户ID、组ID、用户全名、用户主目录和用户登录所用的shell。请设计一个脚本...
在Linux系统的/etc目录下有这样一个文件passwd,该文件里包含系统中所有用户信息的记录,记录里包含每个用户的如下信息:用户名、密码、用户ID、组ID、用户全名、用户主目录和用户登录所用的shell。请设计一个脚本...
最近日常测试中经常需要手动启动或停止docker,于是决定写一个Shell脚本来代替人工操作,另外该脚本,也可以通过Python脚本实行远程调用,详细如下所示: 目前该脚本是将Container ID写死在脚本中,当然也可以通过...
Git指令的Shell脚本,能够快速便捷地管理Git库,包括添加修改、提交修改、显示库状态、推送到远程库、从远程库更新到本地、版本恢复等操作。 使用方法: 1. 在Linux系统中,将本文件放在Git库目录下,利用Shell运行...
最近公司需要在Linux下监控tomcat的服务,一旦tomcat服务存在异常或者宕机,重启tomcat保证服务的正常运行,由于Linux下有Shell脚本可以实现此效果,下面是Linux下shell脚本监控Tomcat的状态并实现自动启动的步骤。...
最近学shell脚本,跟据http://blog.chinaunix.net/uid-26833883-id-3153839.html写了下。
Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行...可以说,shell使用的熟练程度反映了用户对Linux使用的熟练程度。
使用shell脚本安装lnmp,纯粹是偷懒,平时安装一些东西都写成脚本了,方便以后在其他机器安装的时候不用再去查找文档。 PHP版本5.6.6 MYSQL版本5.6.26 NGINX版本1.15.6 2、环境说明 阿里云ECS(1G1核)CentOS 7.4...
Linux根据占用的端口号来关闭相应的进程的shell脚本写法。 代码如下: kill -9 $(lsof -i:22 |awk ‘{print $2}’ | tail -n 2)
1、问题 我们一般很多时候会需要在...3)、思考,为什么每次都需要这样重复的操作呢?一说到重复,我们应该立马想到是否可以用脚本解决重复操作 2、解决办法 通过执行脚本文件获取包名,然后再执行pidcat.py packageNam
aliyun-ddns自动解析域名ip支持ipv6服务器nodejs脚本linux版本 使用说明: 一、获取阿里AccessKey ID和AccessKey Secret。 二、修改config.json配置,填写AccessKey ID、AccessKey Secret、域名地址、解析类型【默认...
了解了一些比较牛的shell命令,将会结你的shell编程产生具大影响,例如column, sshfs, ssh-copy-id,如何直接开辟一段内存空间做为硬盘,用wget直接递归下载网站, !! 代表什么, - 代表什么。都有解答。 如果喜欢就...
不同Linux 系统对用户组的规定有所不同,如Linux下的用户属于与它同名的用户组,这个用户组在创建用户时同时创建。 用户组的管理涉及用户组的添加、删除和修改。组的增加、删除和修改实际上就是对/etc/group文件的...
通常情况下,在工作中用的最多的有如下几项: $0:Shell 的命令本身 1到9:表示 Shell 的第几个参数 $? :显示最后命令的执行情况 $#:传递到脚本的参数个数 $$:脚本运行的当前进程 ID 号 $*:以一个单字符...