黑客往事

软件安全-环境变量攻防

2018-06-01  本文已影响0人  ustc_sec

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,你可以删除文件吗?
不能。

上一篇下一篇

猜你喜欢

热点阅读