SET-UID程序漏洞实验

1  实验简介

Set-UID 是 Unix 系统中的一个重要的安全机制。当一个 Set-UID 程序运行的时候,它被假设为具有拥有者的权限。例如,如果程序的拥有者是root,那么任何人运行这个程序时都会获得程序拥有者的权限。Set-UID 允许我们做许多很有趣的事情,但不幸的是,它也是很多坏事情的罪魁祸首。

因此本次实验的目标有两点:

1. 欣赏好的方面,理解为什么Set-UID是需要的,以及它是如何被执行的。

2. 注意坏的方面,理解它潜在的安全性问题。

2  实验内容

2.1  没有 Set-UID 机制的情况

      猜测为什么“passwd”,“chsh”,“su”,和“sudo”命令需要Set-UID机制,如果它们没有这些机制的话,会发生什么。如果你不熟悉这些程序,可以通过阅读使用手册来熟悉它们。如果你拷贝这些命令到自己的目录下,这些程序就不会是Set-UID程序。

从上面的截图可以看出:将 passwd 拷贝到 /tmp/ 下,权限发生了变化(在原目录下 suid位 被设置),复件没有了修改密码的权限。对于“chsh”,“su”,和“sudo”命令,把这些程序拷贝到用户目录下,同样不再具有root权限。

从这个方面看Set-UID是需要的:passwd命令有一个特殊的权限标记s ,存在于文件所有者的权限位上。这是一类特殊的权限SetUID ,可以这样来理解它:当一个具有执行权限的文件设置SetUID权限后,用户执行这个文件时将以文件所有者的身份执行。passwd命令具有SetUID权限,所有者为root(Linux中的命令默认所有者都是root),也就是说当普通用户使用passwd更改自己密码的时候,那一瞬间突然灵魂附体了,实际在以passwd命令所有者root的身份在执行,root当然可以将密码写入/etc/shadow文件(不要忘记root这个家伙是superuser什么事都可以干),命令执行完成后该身份也随之消失。原文链接:https://blog.csdn.net/Oo__YAN/article/details/7076889

setuid通过使passwd在执行阶段具有文件所有者(也就是root)的权限,让用户临时有了修改shadow文件的能力(当然这种能力是受到限制的)。因此,passwd就是一个经典的setuid程序,其UID是当前执行这个命令的用户ID,而EUID则是root用户的ID(也就是0)。

但是Set-UID存在着安全性问题:使用SetUID可以灵活的调整所有文件所有者权限,但是也为系统的安全性带来了隐患。如果Root用户为指定的程序文件配置过大的SetUID权限,那么就会为黑客或者非法用户打开了侵入系统的大门。例如在Linux中可以使用“vi”命令来编辑文件,但是,对于普通用户而言,当其试图使用命令“vi /etc/shadow”来修改密码文件时,系统就会弹出“/etc/shadow : Permission Denied”的警告提示,从而禁止其对密码文件的非法修改。但是,如果在Root用户环境中执行“which vi”命令,就可以看到“vi”命令实际上是“vim”命令的别名,其真实路径为“/usr/bin/vim”,这样执行命令"chmod 6755 /usr/bin/vim",就可以将“vi”命令的所有者更改为Root,这样在普通的用户环境中,就可以使用“vi”命令来编辑任何文件(例如“/etc/shadow”),这样,即使是普通用户也可以将密码文件清空,从而实现无密码登陆Linux,给系统的安全带来的威胁不言而喻。因此,对可能给系统安全带来危害的程序来说,应该尽量不要随意为其配置SetUID权限。  原文链接:https://blog.csdn.net/frank_jb/article/details/40192003

2.2  运行 Set-UID 程序
       在linux环境下运行Set-UID 程序,同时描述并且解释你的观察结果。
       ●  以 root 方式登录,拷贝 /usr/bin/zsh 到 /tmp, 同时设置拷贝到tmp目录下的zsh为set-uid root权限,然后以普通用户登录,运行 /tmp/zsh。你会得到root权限吗?请描述你的结果。

●  拷贝 /bin/bash 到 /tmp 目录,同时设置 /tmp 目录下的bash为Set-UID root权限,然后以普通用户登录,运行 /tmp/bash。你会得到root权限吗?请描述你的结果。

可见,同样的操作,运行复制的zsh可以获得root权限,而bash不能。

2.3  bash 内在保护机制

从上面步骤可以看出,/bin/bash 有某种内在的保护机制可以阻止Set-UID机制的滥用。为了能够体验这种内在的保护机制出现之前的情形,我们打算使用另外一种shell程序—— /bin/zsh 。在一些linux的发行版中(比如Fedora和Ubuntu),/bin/sh 实际上是/bin/bash 的符号链接。为了使用zsh,我们需要把 /bin/sh 链接到 /bin/zsh。

sh和bash是两个不同的shell,linux下有很多种shell。sh比较小,但是功能没有bash多,bash用得比较普遍 。/bin/sh是/bin/bash的软连接,在一般的linux系统当中,使用sh调用执行脚本相当于打开了bash的POSIX标准模式,也就是说 /bin/sh 相当于 /bin/bash --posix。/bin/sh执行过程中,若出现命令执行失败,则会停止执行;/bin/bash执行过程中,若命令执行失败,仍然会继续执行。

在这里简单说一下软连接:软链接可以理解成快捷方式。它和windows下的快捷方式的作用是一样的,方便我们打开源文件,删除源文件,快捷方式也用不了。

原文链接:https://blog.csdn.net/gao_zhennan/article/details/79127232

下面的指令将会把默认的shell指向zsh:

2.4  PATH环境变量的设置
        system(const char * cmd)系统调用函数被内嵌到一个程序中执行一个命令,system()调用 /bin/sh 来执行shell程序,然后shell程序去执行cmd命令。但是在一个Set-UID程序中system()函数调用shell是非常危险的,这是因为shell程序的行为可以被环境变量影响,比如PATH;而这些环境变量可以在用户的控制当中。通过控制这些变量,用心险恶的用户就可以控制Set-UID程序的行为。
       下面的Set-UID程序被用来执行 /bin/ls 命令;然后程序员可以为ls命令使用相对路径,而不是绝对路径。在 /tmp 目录下新建 test.c 文件:

●  你能够设置这个Set-UID程序运行你自己的代码而不是 /bin/ls 吗?如果你能的话,你的代码具有root权限吗?描述并解释你的观察。

可以具有root权限,把 /bin/sh 拷贝到 /tmp 目录下面重命名为 ls(先要确保 /bin/ 目录下的sh 符号链接到zsh,而不是bash),将环境变量PATH设置为当前目录 /tmp,运行编译的程序test。就可以获得root权限:

我对上述过程的理解为:当输入./test 时,shell 进程通过执行代码中的system(), fork() 创建一个新的子进程,fork复制父进程的环境变量等,此时子进程的环境变量为 PATH=/tmp,子进程在这个环境变量下执行 system("ls"),而在这个环境变量下的 ls 代表着 /bin/sh ,链接至zsh,于是就获得了root权限。

●  先恢复环境变量 PATH ,然后修改 /bin/sh 使得其返回到 /bin/bash ,重复上面的攻击,你仍然可以获得root权限吗?描述并解释你的观察。

可见修改sh连接回bash,运行test程序不能使普通用户获得 root 权限。

2.5  system()和execve()的不同

首先确保 /bin/sh 指向zsh:

然后使用如下命令恢复 PATH:

背景:Bob 在一家审计代理处工作,他正在调查一家公司是否存在诈骗行为。为了这个目的,他需要阅读这家公司在 Unix 系统中的所有文件。为了保护系统的可靠性,他不能修改任何一个文件。为了达到这个目的,Vince——系统的超级用户为他写了一个SET-ROOT-UID程序,并且给了Bob可以执行它的权限。这个程序需要Bob在命令行中打出一个文件名,然后运行 /bin/cat 命令显示这个文件。既然这个程序是以root权限运行的,它就可以显示Bob想看的任何一个文件。然而,既然这个程序没有写操作,Vince很确信Bob不能用这个程序修改任何文件。首先在 /tmp 目录下新建 SRU.c 文件,内容如下:

●  程序中有 q=0。程序会使用system()调用命令行。这个命令安全吗?如果你是Bob,你能对系统的完整性妥协吗?你能重新移动一个对你没有写权限的文件吗?

这个命令不安全,Bob可能会出于好奇或者个人利益驱使阅读或者修改只有root用户才可以运行的一些文件。

比如截图中:file文件只有root用户有读写权限,但普通用户通过运行该程序,阅读并重命名了file文件:

●  如果令q=1;刚才的攻击还会有效吗?请描述并解释你的观察。

修改为q=1后,不会有效。前面步骤之所以有效,是因为system()函数调用 /bin/sh,链接至zsh,具有root权限执行了 cat file 文件后,接着执行 mv file file_new 命令。

而当令q=1, execve()函数会把 file; mv file file_new 看成是一个文件名,系统会提示不存在这个文件:

system() 和exceve() 区别为:执行exec()后,老的进程上下文将被exec出来的新的进程上下文覆盖,新进程代替原进程执行。执行system()后则相当于fork()出一个子进程,并等待此子进程执行完毕。

2.6  LD_PRELOAD环境变量

为了保证Set-UID程序在LD_PRELOAD环境的操纵下是安全的,动态链接器会忽略环境变量,但是在某些条件下是例外的,在下面的任务中,我们猜测这些特殊的条件到底是什么。

1、让我们建立一个动态链接库。把下面的程序命名为 mylib.c ,放在 /tmp 目录下。在函数库 libc 中重载了sleep函数:

2、我们用下面的命令编译上面的程序(注意区别l和1):

3、把下面的程序命名为 myprog.c ,放在 /tmp 目录下:

请在下面的条件下运行这些程序,并观察结果。基于这些观察告诉我们链接器什么时候会忽略LD_PRELOAD环境变量,解释原因。

●  把 myprog 编译成一个普通用户下的程序在普通用户下运行

可见,它会使用LD_PRELOAD环境变量,重载sleep函数:

●  把 myprog 编译成一个Set-UID root的程序在普通用户下运行

在这种情况下,忽略LD_PRELOAD环境变量,不重载sleep函数,使用系统自带的sleep函数:

●  把myprog编译成一个Set-UID root的程序在root下运行

在这种情况下,使用LD_PRELOAD环境变量,使用重载的sleep函数:

●  在一个普通用户下把myprog编译成一个Set-UID 普通用户的程序在另一个普通用户下运行

注意:需要先使用命令 rm myprog 把之前编译生成的 myprog 文件删掉

在这种情况下,不会重载sleep函数:

由以上四种情况可见:只有用户自己创建的程序自己去运行,才会使用LD_PRELOAD环境变量,重载sleep函数,否则的话忽略LD_PRELOAD环境变量,不会重载sleep函数。

2.7  消除和清理特权

为了更加安全,Set-UID程序通常会调用setuid()系统调用函数永久的清除它们的root权限。然而有些时候,这样做是远远不够的。在root用户下,在 /tmp 目录新建一个空文件 zzz。在root用户下将下面代码命名为 test2.c ,放在 /tmp 目录下,编译这个程序,给这个程序设置root权限。在一个普通的用户下,运行这个程序。描述你所观察到的情况,/tmp/zzz 这个文件会被修改吗?解释你的观察。

代码:

结果如图:

如图所示文件被修改了,原因在于设置 uid 前,zzz文件就已经被打开了。只要将语句 setuid(getuid()) 移至调用open函数之前,就能避免这个问题。

setuid()用来重新设置执行目前进程的用户识别码。不过,要让此函数有作用,其有效的用户识别码必须为0(root)。在Linux下,当root 使用setuid()来变换成其他用户识别码时,root权限会被抛弃,完全转换成该用户身份,也就是说,该进程往后将不再具有可setuid()的权 利,如果只是向暂时抛弃root 权限,稍后想重新取回权限,则必须使用seteuid()。执行成功则返回0,失败则返回-1,错误代码存于errno。一般在编写具setuid root的程序时,为减少此类程序带来的系统安全风险,在使用完root权限后建议马上执行setuid(getuid());来抛弃root权限。此外,进程uid和euid不一致时Linux系统将不会产生core dump。

内核会给每个进程关联两个和进程ID无关的用户ID,一个是真实用户ID,还有一个是有效用户ID或者称为setuid(set user ID)。真实用户ID用于标识由谁为正在运行的进程负责。有效用户ID用于为新创建的文件分配所有权、检查文件访问许可,还用于通过kill系统调用向其它进程发送信号时的许可检查。内核允许一个进程以调用exec一个setuid程序或者显式执行setuid系统调用的方式改变它的有效用户ID。

原文链接:https://blog.csdn.net/todd911/article/details/7738069

3  实验总结

      在这次实验中,我通过实践论证了SET-UID这个程序的必要性,以及SET-UID会存在安全隐患,使用SET-UID程序获得root权限后,可以通过setuid()系统调用函数永久的清除它们的root权限,这是一种保护机制以阻止SET-UID的滥用,在实验中,我们也能看到有时候通过这种方式清除是远远不够的,当然还存在一些其他的保护机制,这里就不再介绍了。

2019-2020-12 20199317 《Linux内核原理与分析》 第十二周作业的更多相关文章

  1. 2019-2020-1 20199329《Linux内核原理与分析》第十三周作业

    <Linux内核原理与分析>第十三周作业 一.本周内容概述 通过重现缓冲区溢出攻击来理解漏洞 二.本周学习内容 1.实验简介 注意:实验中命令在 xfce 终端中输入,前面有 $ 的内容为 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第十一周作业

    <Linux内核原理与分析>第十一周作业 一.本周内容概述: 学习linux安全防护方面的知识 完成实验楼上的<ShellShock 攻击实验> 二.本周学习内容: 1.学习& ...

  3. 2019-2020-1 20199329《Linux内核原理与分析》第八周作业

    <Linux内核原理与分析>第八周作业 一.本周内容概述: 理解编译链接的过程和ELF可执行文件格式 编程练习动态链接库的两种使用方式 使用gdb跟踪分析一个execve系统调用内核处理函 ...

  4. 2019-2020-1 20199329《Linux内核原理与分析》第七周作业

    <Linux内核原理与分析>第七周作业 一.本周内容概述: 对Linux系统如何创建一个新进程进行追踪 分析Linux内核创建一个新进程的过程 二.本周学习内容: 1.学习进程的描述 操作 ...

  5. 2019-2020-1 20199329《Linux内核原理与分析》第六周作业

    <Linux内核原理与分析>第六周作业 一.本周内容概述: 学习系统调用的相关理论知识,并使用库函数API和C代码中嵌入汇编代码两种方式使用getpid()系统调用 学习系统调用syste ...

  6. 2019-2020-1 20199329《Linux内核原理与分析》第五周作业

    <Linux内核原理与分析>第五周作业 一.上周问题总结: 虚拟机将c文件汇编成汇编文件时忘记添加include<stdio.h> gdb跟踪汇编过程不熟练 二.本周学习内容: ...

  7. 2019-2020-1 20199329《Linux内核原理与分析》第三周作业

    <Linux内核原理与分析>第三周作业 一.上周问题总结: 第二周头脑风暴完成较慢 虚拟机libc配置错误 书本知识使用不够熟练 二.本周学习内容: 1.实验楼环境虚拟一个x86的CPU硬 ...

  8. 2018-2019-1 20189221 《Linux内核原理与分析》第八周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第八周作业 实验七 编译链接过程 gcc –e –o hello.cpp hello.c / gcc -x cpp-o ...

  9. 2018-2019-1 20189221 《Linux内核原理与分析》第七周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第七周作业 实验六 分析Linux内核创建一个新进程的过程 代码分析 task_struct: struct task ...

  10. 2018-2019-1 20189221 《Linux内核原理与分析》第六周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第六周作业 实验五 实验过程 将Fork函数移植到Linux的MenuOS fork()函数通过系统调用创建一个与原来 ...

随机推荐

  1. CVE-2019-16097:Harbor任意管理员注册漏洞复现

    0x00 Harbor简介 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全.标识和管理等,扩展了开源Docker Distri ...

  2. 视口viewport与单位rem的本质

    结论: 视口viewport的设置是为了让字的显示在不同的屏幕下保持一致. 单位rem的使用是为了让页面中的布局元素的比例在不同的屏幕下显示的比例保持一致. 现象: 我们看电脑时候的网页的时候的字体大 ...

  3. OV5640摄像头配置一些值得注意的关键点(三)

    一.字节标志的注意点 由于摄像头的输出是RGB56格式,所以需要将两帧的数据进行拼接,之后送到上位机进行显示. reg byte_flag; always@(posedge cmos_pclk_i) ...

  4. [考试反思]1005csp-s模拟测试60:招魂

    最近总是好一场烂一场的.没有连续两场排名波动小于20的... 没人管.反正大脸一点脸没有就又AK了. 但是T3爆零这种事情吧... 爆搜不是很难打,但是想优化想了半天剩的时间不够结果赶忙打出来了,然后 ...

  5. Java描述设计模式(17):调停者模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 在公司的日常安排中,通常划分多个部门,每个部门又会分为不同的小组,部门经理的一项核心工作就是协调部门小组之间的工作 ...

  6. 问题 L: 「Usaco2005 Feb」竞选划区O(∩_∩)O 纯属的暴力

    题目描述 农场被划分为5x5的格子,每个格子中都有一头奶牛,并且只有荷斯坦(标记为H)和杰尔西(标记为J)两个品种. 如果一头奶牛在另一头上下左右四个格子中的任一格里,我们说它们相连. 奶牛要大选了. ...

  7. 缓存管理之MemoryCache与Redis的使用

    一..MemoryCache介绍 MemoryCache是.Net Framework 4.0开始提供的内存缓存类,使用该类型可以方便的在程序内部缓存数据并对于数据的有效性进行方便的管理, 它通过在内 ...

  8. MapReduce任务提交源码分析

    为了测试MapReduce提交的详细流程.需要在提交这一步打上断点: F7进入方法: 进入submit方法: 注意这个connect方法,它在连接谁呢?我们知道,Driver是作为客户端存在的,那么客 ...

  9. 手把手带你实战下Spring的七种事务传播行为

    目录 本文目录 一.什么是事务传播行为? 二.事务的7种传播行为 三.7种传播行为实战 本文介绍Spring的七种事务传播行为并通过代码演示下. 本文目录 一.什么是事务传播行为? 事务传播行为(pr ...

  10. java基础阶段几个面试题

    1.说出你对面向对象的理解 在我理解,面向对象是向现实世界模型的自然延伸,这是一种“万物皆对象”的编程思想.在现实生活中的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例.面向对象的编程是以 ...