关闭

Set-UID程序漏洞实验

标签: set-uid权限运行机制
445人阅读 评论(0) 收藏 举报
分类:

SET-UID程序漏洞实验

实验简介

Set-UID 是Unix系统中的一个重要的安全机制。当一个Set-UID程序运行的时候,它被假设为具有拥有者的权限。例如,如果程序的拥有者是root,那么任何人运行这个程序时都会获得程序拥有者的权限。
本次试验试图理解Set-UID运行机制的原理,并利用这一机制获取root权限。

实验内容

1.理解Set-UID机制

在使用操作系统的过程中,普通用户有可能临时需要使用系统权限,如修改密码passwd、管理员权限运行sudo等,在使用这种程序的时候,普通用户的权限被提升到root(即文件的所有者)级别,因此可以完成用户本无权进行的操作。
通过实验,我们可以观察到用户提权的过程。我们首先以root的身份创建一个zsh作为运行的目标shell,并赋予Set-UID权限。

# cp/usr/bin/zsh /tmp
# chmod u+s /tmp/zsh

在普通用户权限下执行/tmp/zsh,可以发现普通用户得到了root权限#,此时我们可以完成所有使用root权限才能完成的操作。
如果我们使用普通用户创建这个zsh,则不会拥有root权限。

$ cp /usr/bin/zsh /tmp
$ chmod u+s /tmp/zsh

这是因为在复制时,文件的所有者是普通用户,Set-UID仅仅为zsh赋予了普通用户的权限,而没有root权限。
经实验,拥有Set-UID权限的zsh可以让我们获取到root权限,我们再尝试使用bash是否也可以达到这样的效果。

# cp/usr/bin/bash /tmp
# chmod u+s /tmp/bash
$ /tmp/bash

我们可以看到,虽然进入了bash,但是并没有获得到root权限bash-4.3$。/bin/bash有某种内在的保护机制可以阻止Set-UID机制的滥用。为了能够体验这种内在的保护机制出现之前的情形,我们打算使用另外一种shell程序——/bin/zsh。在一些linux的发行版中(比如Redora和Ubuntu),/bin/sh实际上是/bin/bash的符号链接。为了使用zsh,我们需要把/bin/sh链接到/bin/zsh:ln -s /bin/zsh /bin/sh

2.利用Set-UID权限获取root权限

(1)system()函数的功能

在C语言程序中,可以使用system()函数来调用环境变量PATH中的程序。如system("ls")可以打印当前文件夹下的文件列表。

(2)利用system函数获取root权限

既然system函数可以运行PATH中的程序,而PATH又存在拥有Set-UID权限的zsh,那么我们就可以通过执行这个程序来获取root权限。

//SetUID.c
int main()
{
    system("zsh");
}

使用root权限编译,并赋予Set-UID权限。普通用户身份运行。

# gcc SetUID.c -o SetUID
# chmod u+s SetUID
$ ./SetUID

我们会发现,我们获得了root权限#

(3)理解sytem()和execve()的不同

首先我们来看一段代码。

#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.\n");
        return 1;
    }
    v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = 0;
    //Set q = 0 for Question a, and q = 1 for Question 
    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()方式,否则使用execve方式。然而前一种方式是不安全的。
我们构造输入文件名如下:SetUID.c;rm -rf /。使用system()解析时,会直接把输入当作shell语句,因此结果为:cat SetUID.c; rm -rf /文件安全遭受到威胁。
使用execve方式不会存在这个问题,因为execve把cat SetUID.c; rm -rf /处理为耽搁文件名,会提示文件不存在。

3.理解LD_PRELOAD环境变量的作用

为了理解LD_PRELOAD环境变量,我们先重载libc中的一个函数。

//mylib.c
#include <stdio.h>
void sleep(int t)
{
    printf("I don't want to sleep for %d seconds.\n", t);
}

编译上面的程序:
gcc -fPIC -g -c mylib.c
gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.1 mylib.o –lc
再写一个用户程序调用sleep函数:

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

首先我们以普通用户身份编译运行。我们会发现运行结果为:I don't want to sleep for 1 seconds.

$ gcc test.c -o test
$ ./test

我们尝试把test.c编译一个带root权限的Set-UID程序,以普通用户身份运行。不会重载sleep函数。

# gcc test.c -o test
# chmod u+s test
$ ./test

我们尝试把test.c编译一个带root权限的Set-UID程序,以root身份运行。运行结果为:I don't want to sleep for 1 seconds.

# gcc test.c -o test
# chmod u+s test
# ./test

最后我们把test.c编译一个带普通用户权限的Set-UID程序,以普通用户身份运行。sleep没有被重载。

$ gcc test.c -o test
$ chmod u+s test
$ ./test

通过上面的实验,我们可以得到结论,只有用户自己创建的程序自己去运行,才会使用LD_PRELOAD环境变量,重载sleep函数,否则的话忽略LD_PRELOAD环境变量,不会重载sleep函数。

4.Set-UID的提权和清除

有些时候,我们希望用户临时获取root权限进行一些操作,结束后恢复其自身权限,这个时候我们就需要清除Set-UID权限。

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

需要注意的一点是,setuid(getuid());必须放在文件打开之前,文件一旦被打开,普通用户就拥有了写入权限。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8634次
    • 积分:229
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类