Loading... # 环境变量攻击 ## 环境变量 * 一组动态的定义值 * OS运行环境的一部分 * 影响正在运行进程的行为方式(加载哪些外部DLL) * 当执行一个程序时,如果没有提供完整的路径,shell进程将使用环境变量来找到程序的位置 使用Windows系统,我们安装编程相关软件时有时会问是否加入到环境变量,比如python(最好要加),这样我们在任何目录下cmd都可以运行python(现在本目录下找,没有就去环境变量里找) ## 如何访问环境变量 计算机右键属性>高级系统设置>环境变量 ![image-20221112224205107.png](http://xherlock.top/usr/uploads/2022/11/508233834.png) 代码访问环境变量 ![image-20221112224409693.png](http://xherlock.top/usr/uploads/2022/11/3273684751.png) 编译运行后如下 ![image-20221112224614565.png](http://xherlock.top/usr/uploads/2022/11/4077431811.png) 更简单的方法是printenv或env查看环境变量 ![image-20221112225034470.png](http://xherlock.top/usr/uploads/2022/11/3145814804.png) **查看特定变量的方法**:env | grep variable,或直接printenv variable ![image-20221112225117641.png](http://xherlock.top/usr/uploads/2022/11/2598323289.png) ![image-20221112225123304.png](http://xherlock.top/usr/uploads/2022/11/1930952087.png) **设置自己的环境变量**:export variable=value ![image-20221112225315241.png](http://xherlock.top/usr/uploads/2022/11/637627054.png) ![image-20221112225325512.png](http://xherlock.top/usr/uploads/2022/11/3059549696.png) **清除自定义的环境变量**:unset variable ![image-20221112225356032.png](http://xherlock.top/usr/uploads/2022/11/2742011032.png) **进程**如何获取环境变量 * fork()创建一个新进程,则子进程将继承其父进程的环境变量 ~~~c #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]); i++; } } void main() { pid_t childPid; switch(childPid = fork()) { case 0: /* child process */ printenv(); exit(0); default: /* parent process */ // printenv(); exit(0); } } ~~~ **代码解释**:父进程fork后返回子进程id给pid,由于不为0将执行default中内容,在子进程中,fork返回0,执行case 0里的内容 https://blog.csdn.net/hzrandd/article/details/50724697 http://www.csl.mtu.edu/cs4411.ck/www/NOTES/process/fork/create.html 分别注释两个进程,编译运行后打印环境变量,可以看到fork的父子进程环境变量一模一样 ![image-20221112225727434.png](http://xherlock.top/usr/uploads/2022/11/4264793792.png) * execve()启动一个新程序,在此场景中内存空间被覆盖,旧环境变量将丢失 ~~~c #include <unistd.h> extern char **environ; int main() { char *argv[2]; argv[0] = "env"; argv[1] = NULL; execve("/usr/bin/env", argv, NULL); return 0 ; } ~~~ 运行后打印环境变量为空 int execve(const char *filename, char *const argv[ ], char *const envp[ ]); * filename:执行命令的文件路径 * argv[ ]:使用数组指针来传递给执行文件,必须以NULL结尾 * envp[ ]:传递给执行文件的新环境变量数组 execve传递给新进程旧环境变量的方法:NULL改为外部变量environ,也可以传递自定义的环境变量 ## /proc文件系统 /proc是linux下的一个虚拟文件系统,包含每个进程的一个目录,使用进程ID作为目录名称 * 每个进程目录都有一个名为environ的虚拟文件,其中包含进程的环境 * 查看当前进程的环境变量:strings /proc/$$/environ (shell自动将\$\$替换为进程ID) ## shell命名变量 当shell程序启动时,会将环境变量复制到自己的shell变量中,对shell变量的改动不会改动环境变量 ![image-20221113095809405.png](http://xherlock.top/usr/uploads/2022/11/1426947799.png) 如下图:显示了shell变量如何影响子进程的环境变量;同时显示了父shell的环境变量如何成为子进程的环境变量 ![image-20221113095852333.png](http://xherlock.top/usr/uploads/2022/11/41063094.png) 从图中可以看到:只有**原本的环境变量**、**export设置的环境变量**才可以进入进程新建的子进程(反映在下图就是LOGNAME2没有出现在子进程的环境变量中【env执行,shell将创建一个子进程】) ![image-20221113100137740.png](http://xherlock.top/usr/uploads/2022/11/2791599890.png) ## 环境变量的攻击 ### 通过Set-UID攻击 #### Set-UID * 允许用户以程序所有者的权限运行程序 * 允许用户以临时提升的权限运行程序 在UNIX中,每个进程都有两个用户ID * real UID(**RUID**):确定进程的真正所有者 * effective UID(**EUID**):标识进程的权限(访问控制) 当执行正常程序时,RUID=EUID=**运行程序的用户的ID**;当执行Set-UID时,RUID≠EUID,RUID还是运行程序的用户的ID,EUID是程序所有者的ID 即,若程序归root所有,执行set-UID将以root权限执行 #### 攻击 由于用户可以设置环境变量,因此可以将其作为set-UID程序攻击的一部分 1. 添加/home/seed 目录到 PATH 环境变量中,使用export,冒号是分割的作用 ![image-20221113103014341.png](http://xherlock.top/usr/uploads/2022/11/2581660572.png) 2. 编写使用 system 调用 ls 的程序 ![image-20221113103111796.png](http://xherlock.top/usr/uploads/2022/11/4181706813.png) 3. 编译后修改所有者权限,使之称为set-UID程序 ![image-20221113103152122.png](http://xherlock.top/usr/uploads/2022/11/1482215983.png) **补充**:4755(4 表示**其他用户**执行文件时具有与所有者相当的权限;7 表示**文件所有者**的权限为全部;5 表示**与文件所有者同属一个用户组的其他用户**的权限为可读可执行;第二个 5 表示**其他用户组**的权限为可读可执行) 4. 执行后发现输出 ls 打印的内容 ![image-20221113104054541.png](http://xherlock.top/usr/uploads/2022/11/3489562248.png) 5. 我们可以利用之前添加的路径/home/seed,将/bin/sh 拷贝到那里并修改为 ls,这时再去执行 ls 其实会直接执行 sh,获取 shell,但是发现没有获取的 root 权限,uid 没有发生变化 ![image-20221113104219295.png](http://xherlock.top/usr/uploads/2022/11/1674954346.png) 6. 主要原因是/bin/sh 链接到了/bin/dash,具有一定的防御措施,检测到 uid 攻击后会将 euid 设置回进程真实的 uid,因此我们做一定的修改,将/bin/sh 链接到/bin/zsh,此时获取 root 权限(多了个euid=0,Set-UID 程序和其他 UNIX 程序的唯一区别是具有 **Set-UID 比特位**) ![image-20221113110338238.png](http://xherlock.top/usr/uploads/2022/11/4292045182.png) ### 通过动态链接器攻击 #### 动态链接 链接再运行时完成,在运行使用动态链接编译的程序前,首先将其可执行文件加载到内存(静态链接生成的程序比动态链接生成的大得多) * LD_PRELOAD包含一个共享库的列表,链接器将首先搜索它 * 如果没有找到所有函数,链接器将在几个文件夹中搜索,包括**LD_LIBRARY_PATH**指定的文件夹 * 这两个变量可以被用户设置,使得有机会控制链接过程 #### 攻击 1. 编写 sleep 函数的 lib 文件 ![image-20221113114130706.png](http://xherlock.top/usr/uploads/2022/11/1853701222.png) 2. 编译文件(-shared 生成共享目标文件,通常用在建立共享库时) ![image-20221113114153713.png](http://xherlock.top/usr/uploads/2022/11/4018508584.png) 3. 设置 LD_PPRELOAD 环境变量为之前生成的共享目标文件 ![image-20221113114207723.png](http://xherlock.top/usr/uploads/2022/11/1015858974.png) 4. 编写 myprog.c 并编译运行,可以看到并没有调用本来的 sleep,而是调用了我们编写的 带有 printf 的 sleep ![image-20221113114343654.png](http://xherlock.top/usr/uploads/2022/11/4049724587.png) ![image-20221113114348171.png](http://xherlock.top/usr/uploads/2022/11/2151626558.png) 5. 但是如果程序为set-UID程序,程序没有调用我们自定义的链接库 ![image-20221113114606835.png](http://xherlock.top/usr/uploads/2022/11/3570116064.png) 原因:动态链接器实现了一个对策,当EUID和RUID不同时,它会忽略LD_PRELOAD和LD_LIBRARY_PATH环境变量 示例:复制env程序,并将其设置为Set-UID程序;导出上面两个环境变量 ![image-20221113114820337.png](http://xherlock.top/usr/uploads/2022/11/2051612310.png) ![image-20221113114824895.png](http://xherlock.top/usr/uploads/2022/11/3223854325.png) ### 通过外部程序攻击 应用程序可以调用外部程序,本身可能不使用环境变量,但是被调用的外部程序可能会使用 **方法** * 执行exec()家族 * system(),调用execl,execl调用execve运行/bin/sh,然后shell运行程序 与system()相比,execve()攻击面更小,不受环境变量影响;当在特权程序中调用外部程序时,应该使用execve() 其他方法:通过外部库、应用程序代码攻击 最后修改:2022 年 11 月 13 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏