首页
视频
资源
登录
原
Linux权限管理 no_new_privs
6500
人阅读
2022/4/19 17:01
总访问:
2136820
评论:
0
收藏:
0
手机
分类:
linux
 >#Linux权限管理 no_new_privs [TOC] ## setuid和setgid简介 tn2>setuid和setgid位是让普通用户可以以root用户的角色运行只有root帐号才能运行的程序或命令。比 如我们用普通用户运行passwd命令来更改自己的口令,实际上最终更改的是`/etc/passwd`文件我们知道`/etc/passwd`文件是用户管理的 配置文件,只有root权限的用户才能更改。 ```bash useradd bob whoami ls /etc/passwd -al ```  tn2>作为普通用户如果修改自己的口令通过修改`/etc/passwd`肯定是不可完成的任务,但是不是可以通过一个命令来修改呢答案是肯定的,作为普通用 户可以通过`passwd`来修改自己的口令这归功于passwd命令的权限我们来看一下;  tn2>因为`/usr/bin/passwd`文件已经设置了setuid 权限位(也就是r-s--x--x中的s),所以普通用户能临时变成root,间接的修改`/etc/passwd`,以达到修改自己口令的权限 我们在Linux 系统中的超级权限的控制中 有提到过我们知道Linux的用户管理是极为严格的,不同的用户拥有不同的权限,为了完成只有root用户才能完成的工作,我们必须为普通用户提升权 限,最常用的方法就是su或sudo虽然setuid 和setgid也是让普通用户超越自身拥有的普通权限达到root权限的方法,但我不推荐大家使用,因为它能为系统带来隐患!! tn>注意:setuid和setgid会面临风险,所以尽可能的少用 ## setuid和setgid的实例应用 tn2>我们想让一个普通用户 bob 拥有root用户拥有超级rm删除权限,我们除了用su或sudo 临时切换到 root身份操作以外,还能怎么做呢?   tn2>那我们怎么才能让 bob 这个普通用户也拥有root超级的rm 删除能力呢?   tn2>我们只是设置了rm的setuid位,让普通用户在rm指令上有超级root的删除超级权力。 通过这个例子,我们应该能明白setuid和setgid位的应用了,如同前面所说,让普通用户超越本身的能力,让普通用户能执行只有root才能 执行的命令在这一点,我们要和su和sudo 区分开来请参见su和sudo的文档:Linux 系统中的超级权限的控制 ## setuid和setgid的设置方法 >### 八进制方法 tn2>setuid位是的设置用八进制的4000,setgid占用的是八进制的2000 ;比如我们前面所说的 `chmod 4755 /bin/rm`就是设置的setuid位; 至于setuid的设置方法,只是在我们通过chmod设置文件或目录权限位的八进制方法的前面多加一个数字,也就是4比如:  tn2>作为setgid 位占用的是八进制的2000位,我们下面举个例子;  tn2>我们看到 aa 这个目录,经过改变权限后的,目录所归属用户组的那三个权限位是 r-s 如果我们见到的是小写的s,表明文件所归属的用户组位有执行权限x因为我们用了`2755` ,意思是说文件属主拥有可读可写可执行权限,所归属的用户组拥有可读可执行权限,并且设置了setgid,所以这时本来文件所归属的用户组拥有`r-x`,现 在加了setgid位,就把其中的x换成了s如果文件所归属的用户组没有执行权限,这个权限应该是S同理 setgid 位的中的大写的S和小写的s,也 是这个原理见下面的例子;  tn2>这个例子是因为目录 aa 所归属的组没有执行权限,这时本来在执行权限位上显示-,由于有了setgid,所以显示为S。 如果我们为一个文件的权限拥有 属主可读可写可执行所归的组拥有可读可执行,其它用户可读可执行,并且同时设置setuid和setgid位,我们应该怎么运行命令呢?  tn2>所以,同时设置setuid和setgid,就是把setuid和setgid两个八进位的值相加 (4000+2000=6000),然后加上文件或目录的权限位的三位数值(上面的例子是755),然后通过chmod 运行就行了所以上面例子中用了6755 >### 通过助记语法 tn2>还是延用 chmod 的助记语法,通过 `u+s` 或 `u-s` 来增减setuid位,同理,我们可以通过 `g+s` 或 `g-s` 来setgid位; ```bash chmode u+s aa.txt chmode u-s aa.txt ``` tn2>我们也可以用file命令来查看setuid和setgid位,当然也能用 file 来查看文件的类型:  ## execve tn2>execve(执行文件)在父进程中fork一个子进程,在子进程中调用exec函数启动新的程序。 execve 系统调用能够赋予最新启动的进程其父进程没有的权限。 tn>最常见的例子就是通过 setuid和setgid来设置程序进程的uid以及gid以及文件的访问权限。(子进程)同样继承了父进程的权限,在内核以及用户代码中必须小心这些权限信息,避免造成子进程崩溃。 tn2>举例:我们编写一个简单的c程序`bobexe.c`,查看`/etc/passwd`文件的权限,文件内容如下: ```c #include<unistd.h> int main() { char * argv[ ]={"ls","-al","/etc/passwd",(char *)0}; char * envp[ ]={"PATH=/bin",0}; execve("/bin/ls",argv,envp); } ``` ```bash gcc -g bobexe.c -o bobexe ./bobexe ```  ## fork函数 tn2>fork函数可以复制当前的进程,它会返回两次,执行fork函数的进程称之为父进程,复制出来的进程为子进程,在父进程中会返回复制出来子进程的pid,而子进程中的返回值为0。 tn>一、fork函数不会复制父进程的内存空间,子进程用的是父进程的内存空间,在这种情况下,父进程与子进程共享内存空间 二、子进程有一个复制出来的内存空间,子进程有一个自己单独可用的内存空间 tn2>在复制进程时,上述两种情况都会发生。fork函数调用时,父子进程共用内存空间,父子进程可以同时读取内存空间的数据。如图1但是当我们在任意一个进程中尝试修改内存空间的数据,内存就会复制一份给修改方单独使用,避免影响其他进程的运行。顾名思义,这个内存空间就叫写时复制页(copy on write,cow),如图2   ## no_new_privs tn2>一般情况下,`execve()` 系统调用能够赋予新启动的进程其父进程没有的权限,最常见的例子就是通过 `setuid` 和 `setgid` 来设置程序进程的 uid 和 gid 以及文件的访问权限。这就给不怀好意者钻了不少空子,可以直接通过 fork 来提升进程的权限,从而达到不可告人的目的。 >为了解决这个问题,Linux 内核从 3.5 版本开始,引入了 `no_new_privs` 属性(实际上就是一个 bit,可以开启和关闭),提供给进程一种能够在 execve() 调用整个阶段都能持续有效且安全的方法。 1. 开启了 no_new_privs 之后,execve 函数可以确保所有操作都必须调用 execve() 判断并赋予权限后才能被执行。这就确保了线程及子线程都无法获得额外的权限,因为无法执行 setuid 和 setgid,也不能设置文件的权限。 2. 一旦当前线程的 no_new_privs 被置位后,不论通过 fork,clone 或 execve 生成的子线程都无法将该位清零。 tn2>Docker 中可以通过参数 `--security-opt` 来开启 `no_new_privs` 属性,例如:`docker run --security-opt=no_new_privs busybox`。下面通过一个例子来体会一下 no_new_privs 属性的作用。 首先撸一段 C 代码,显示当前进程的有效用户 id: ```bash mkdir cctest cd cctest vim testnnp.c ``` ```c #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main(int argc, char *argv[]) { printf("Effective uid: %d\n", geteuid()); return 0; } ``` ```bash make testnnp ```  tn2>将可执行文件打入 docker 镜像中: ```bash FROM fedora:latest ADD testnnp /root/testnnp RUN chmod +s /root/testnnp ENTRYPOINT /root/testnnp ```  tn2>构建镜像: ```bash docker build -t testnnp . ```  tn2>下面来做两个实验,先在没有开启 `no-new-privileges` 的情况下启动容器: ```bash docker run -it --rm --user=1000 testnnp ```  tn2>从输出结果来看,只要给可执行文件设置了 SUID 标识,即使我们使用普通用户(UID=1000)来运行容器,进程的有效用户也会变成 root。 接着在开启 `no-new-privileges` 的前提下启动容器,以防止执行设置了 SUID 标识的可执行文件进行 UID 转换: ```bash docker run -it --rm --user=1000 --security-opt=no-new-privileges testnnp ```  tn2>可以看到,开启了 `no_new_privs` 属性之后,即使可执行文件设置了 SUID 标识,线程的有效用户 ID 也不会变成 root。这样即使镜像中的代码有安全风险,仍然可以通过防止其提升权限来避免受到攻击。 ## 关于Kubernetes中的运用 tn2>Kubernetes 也可以开启 `no_new_privs`,不过逻辑稍微复杂一点。当 Pod 的 SecurityContext定义下的 `allowPrivilegeEscalation` 字段值为 false 时(默认就是 false),如果不满足以下任何一个条件,就会开启 `no_new_privs` 属性: - 设置了 `privileged=true` - 增加了 `CAP_SYS_ADMIN` capabilities,即 `capAdd=CAP_SYS_ADMIN` - 以 root 用户运行,即 UID=0 tn2>例如,当设置了 `privileged=true` 和 `allowPrivilegeEscalation=false` 时,就不会开启 no_new_privs 属性。同理,设置了 `capAdd=CAP_SYS_ADMIN` 和 `allowPrivilegeEscalation=false` 也不会开启 no_new_privs 属性。
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}
尘叶心繁
这一世以无限游戏为使命!
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
.net后台框架
160篇
linux
17篇
linux中cve
1篇
windows中cve
0篇
资源分享
10篇
Win32
3篇
前端
28篇
传说中的c
4篇
Xamarin
9篇
docker
15篇
容器编排
101篇
grpc
4篇
Go
15篇
yaml模板
1篇
理论
2篇
更多
Sqlserver
4篇
云产品
38篇
git
3篇
Unity
1篇
考证
2篇
RabbitMq
23篇
Harbor
1篇
Ansible
8篇
Jenkins
17篇
Vue
1篇
Ids4
18篇
istio
1篇
架构
2篇
网络
7篇
windbg
4篇
AI
17篇
threejs
2篇
人物
1篇
嵌入式
2篇
python
8篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2023
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术