zoukankan      html  css  js  c++  java
  • 20199324《Linux内核原理与分析》第十一周作业

    SET-UID程序漏洞实验

    一、实验简介

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

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

    • 欣赏好的方面,理解为什么 Set-UID 是需要的,以及它是如何被执行的。
    • 注意坏的方面,理解它潜在的安全性问题。

    二、实验内容

    这是一个探索性的实验,你的任务是在Linux环境中和Set-UID机制”玩游戏“,你需要在Linux中完成接下来的实验任务:

    2.1 没有 Set-UID 机制的情况

    猜测为什么“passwd”,“chsh”,“su”,和“sudo”命令需要Set-UID机制,如果它们没有这些机制的话,会发生什么。

    如果你不熟悉这些程序,可以通过阅读使用手册来熟悉它们。如果你拷贝这些命令到自己的目录下,这些程序就不会是Set-UID程序。

    $ cp /usr/bin/passwd /tmp/passwd
    $ ls -la /usr/bin/passwd
    $ ls -la /tmp/passwd
    $ /tmp/passwd #shiyanlou密码可以通过点击右侧工具栏SSH直连看到
    $ /usr/bin/passwd
    

    从上面的截图可以看出:将 passwd 拷贝到 /tmp/ 下,权限发生了变化(在原目录下 suid位 被设置),复件没有了修改密码的权限。

    对于“chsh”,“su”,和“sudo”命令,把这些程序拷贝到用户目录下,同样不再具有root权限。

    2.2 运行 Set-UID 程序

    在linux环境下运行Set-UID 程序,同时描述并且解释你的观察结果。

    • 以root方式登录,拷贝/usr/bin/zsh 到/tmp, 同时设置拷贝到tmp目录下的zsh为set-uid root权限,然后以普通用户登录,运行/tmp/zsh。

    • 拷贝/bin/bash到/tmp目录,同时设置/tmp目录下的bash为Set-UID root权限,然后以普通用户登录,运行/tmp/bash。

    可见,同样的操作,运行复制的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。

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

    $ sudo su
    # cd /bin
    # rm sh
    # ln -s zsh sh
    

    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 文件:

    int main()
    {
       system("ls");
       return 0;
    }
    
    • 你能够设置这个Set-UID程序运行你自己的代码而不是/bin/ls吗?如果你能的话,你的代码具有root权限吗?描述并解释你的观察。

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

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

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

    2.5 system()和execve()的不同

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

    $ sudo su
    # cd /bin
    # rm sh
    # ln -s zsh sh
    

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

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
    

    首先在 /tmp 目录下新建 SRU.c 文件,内容如下:

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    int main(int argc, char *argv[])
    {
       char *v[3];
       if(argc < 2)
       {
       printf("Please type a file name.
    ");
       return 1;
       }
       v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = 0;
      //Set q = 0 for Question a, and q = 1 for Question b
       int q = 0;
       if (q == 0)
       {
          char *command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
          sprintf(command, "%s %s", v[0], v[1]);
          system(command);
      }
      else execve(v[0], v, 0);
      return 0 ;
    }
    
    • 程序中有 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 看成是一个文件名,系统会提示不存在这个文件:

    2.6 LD_PRELOAD环境变量

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

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

    #include <stdio.h>
    void sleep (int s)
    {
        printf("I am not sleeping!
    ");
    }
    

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

    gcc -fPIC -g -c mylib.c
    
    gcc -shared -Wl,-soname,libmylib.so.1 
    -o libmylib.so.1.0.1 mylib.o –lc
    

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

    int main()
    {
       sleep(1);
       return 0;
    }
    

    在下面的条件下运行这些程序,并观察结果。基于这些观察告诉我们链接器什么时候会忽略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这个文件会被修改吗?解释你的观察。

    代码:

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    int main(){
    
        int fd;
        fd = open("/tmp/zzz",O_RDWR|O_APPEND);
        sleep(1);
        setuid(getuid());
        pid_t pid ;
    
        if( ( pid = fork() ) < 0 )
            perror("fork error");
        else if( pid == 0 ){
            // child process
            write( fd , "shiyanlou!" , 10 );
        }
    
        int status=waitpid(pid,0,0);
        close(fd);
    
        return 0;
    }
    

    结果如图:

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

  • 相关阅读:
    null in ABAP and nullpointer in Java
    SAP ABAP SM50事务码和Hybris Commerce的线程管理器
    Hybris service layer和SAP CRM WebClient UI架构的横向比较
    SAP ABAP和Linux系统里如何检查网络传输的数据量
    SAP CRM WebClient UI和Hybris的controller是如何被调用的
    SAP CRM和Cloud for Customer订单中的业务伙伴的自动决定机制
    SAP CRM WebClient UI和Hybris CommerceUI tag的渲染逻辑
    SAP BSP和JSP页面里UI元素的ID生成逻辑
    微信jsapi支付
    微信jsapi退款操作
  • 原文地址:https://www.cnblogs.com/yangdd/p/11944969.html
Copyright © 2011-2022 走看看