seed-labs 软件部分- 环境变量攻击
环境变量实现攻击
环境变量
环境变量是存储在进程中的一系列动态键值,它们可以影响进程的行为。
当shell进程执行一个程序时,如果该程序的完整路径没有给出,shell将从PATH环境变量提供的目录中寻找该程序。
如何访问环境变量
C语言执行时main函数第三个参数指向了环境变量数组,所以在main()函数中,可以使用envp[]数组来获取环境变量值。
envp数组只能在main()函数中使用。环境变量还可以通过environ这个全局变量来访问,该变量指向环境变量数组。(建议使用environ这个全局变量来访问:环境变量在内存中的位置中讲到)
程序还可以使用getenv(var_name)函数来获取一个具体的环境变量的值。这个函数实际上是在environ数组中搜索指定环境变量的值。程序可以使用putenv()、setenv()和unsetenv()函数来分别增加、修改、删除环境变量。
进程获取环境变量的方式
第一种,如果是一个新建立的进程,即使用fork()系统调用(在UNIX中)生成的进程,这种情况下,子程序的内存是父进程内存的副本,也就是说子进程将继承父进程的所有环境变量。
第二种:如果进程自身通过execve()系统调用运行一个新的程序(而不是在子进程中运行),进程的内存将会被新的程序覆盖,因此进程中存储的所有的环境变量将会丢失。如果进程希望将环境变量传递给新运行的程序,它
execve()函数有三个参数:filename指向要运行的新程序路径,argv包含新程序的所有参数,envp包含新程序的环境变量。
int execve(const char *filename, char *const argv[], char *const envp[])
接下来看一下execve()函数是如何决定进程的环境变量的。
执行了一个名为/usr/bin/env的新程序,该程序打印了当前进程的环境变量。定义个newenv数组,用它作为execve( )函数的第三个参数。也可以用environ和NULL作为第三个参数。
环境变量在内存中的位置
当1中的环境变量发生改边后,1、2区域可能会出现空间不够的情况,这个时候整个环境变量可能会转移到其它位置,这时候全局变量environ也许做相应的更改才能使environ一直指向环境变量区域。但是envp参数指向的位置却不会改变,所以在这种情况下envp方式它还是指向旧的区域,就获得不了我们想要的环境变量了
环境变量带来的攻击面
[05/21/21]seed@VM:~/env$ gcc -o hello_dynamic hello.c
[05/21/21]seed@VM:~/env$ ll
total 12
-rw-rw-r-- 1 seed seed 74 May 21 05:19 hello.c
-rwxrwxr-x 1 seed seed 7348 May 21 05:19 hello_dynamic
[05/21/21]seed@VM:~/env$ gcc -static -o hello_static hello.c
[05/21/21]seed@VM:~/env$ ll
total 724
-rw-rw-r-- 1 seed seed 74 May 21 05:19 hello.c
-rwxrwxr-x 1 seed seed 7348 May 21 05:19 hello_dynamic
-rwxrwxr-x 1 seed seed 728320 May 21 05:20 hello_static
[05/21/21]seed@VM:~/env$
案例分析 ld_preload ld_library_path
[05/23/21]seed@VM:~/env$ ls
hello.c hello_dynamic hello_static libmylib.so.1.0.1 mytest mytest.c sleep.c sleep.o
[05/23/21]seed@VM:~/env$
通过外部程序进行攻击
两种攻击方式
一种是exec()函数,最终将使用execve()系统调用外部程序载入内存并执行。
还有就是system()函数,先通过fork() 函数创建子进程,然后用execl()函数运行外部程序,最终调用execve()函数
shell程序会使用很多的外部输入,因此他的攻击面比一般程序要大。
许多环境变量会影响shell程序,最常见的就是PATH
“strings /proc/$$/environ” 可以打印出环境变量
系统的环境变量都/proc这个目录下
[05/26/21]seed@VM:~/env$ strings /proc/$$/environ
XDG_SEAT=seat0
XDG_SESSION_ID=c1
LD_LIBRARY_PATH=/home/seed/source/boost_1_64_0/stage/lib:/home/seed/source/boost_1_64_0/stage/lib:
GIO_LAUNCHED_DESKTOP_FILE_PID=2514
DISPLAY=:0
UPSTART_JOB=unity7
JOB=unity-settings-daemon
COLORTERM=gnome-terminal
GNOME_KEYRING_CONTROL=
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path
QT_QPA_PLATFORMTHEME=appmenu-qt5
LOGNAME=seed
INSTANCE=
JAVA_HOME=/usr/lib/jvm/java-8-oracle
SHELL=/bin/bash
PATH=/home/seed/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:.:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
IM_CONFIG_PHASE=1
QT4_IM_MODULE=xim
CLUTTER_IM_MODULE=xim
XMODIFIERS=@im=ibus
SESSION=ubuntu
J2REDIR=/usr/lib/jvm/java-8-oracle/jre
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
UPSTART_EVENTS=xsession started
XDG_SESSION_DESKTOP=ubuntu
GDMSESSION=ubuntu
XAUTHORITY=/home/seed/.Xauthority
QT_IM_MODULE=ibus
GIO_LAUNCHED_DESKTOP_FILE=/usr/share/applications/terminator.desktop
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg
MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path
UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1118
DESKTOP_SESSION=ubuntu
XDG_RUNTIME_DIR=/run/user/1000
GTK_IM_MODULE=ibus
GTK_MODULES=gail:atk-bridge:unity-gtk-module
USER=seed
PWD=/home/seed
LIBGL_ALWAYS_SOFTWARE=1
DERBY_HOME=/usr/lib/jvm/java-8-oracle/db
UPSTART_INSTANCE=
TERMINATOR_UUID=urn:uuid:05ec7694-b580-47a3-976c-897002a85944
IBUS_DISABLE_SNOOPER=1
HOME=/home/seed
QT_ACCESSIBILITY=1
ORBIT_SOCKETDIR=/tmp/orbit-seed
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop
LANGUAGE=en_US
COMPIZ_BIN_PATH=/usr/bin/
COMPIZ_CONFIG_PROFILE=ubuntu-lowgfx
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/seed
LANG=en_US.UTF-8
GTK2_MODULES=overlay-scrollbar
GPG_AGENT_INFO=/home/seed/.gnupg/S.gpg-agent:0:1
SHLVL=0
WINDOWID=60817412
J2SDKDIR=/usr/lib/jvm/java-8-oracle
XDG_VTNR=7
GDM_LANG=en_US
SESSIONTYPE=gnome-session
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-CZIABrSpBw
XDG_CURRENT_DESKTOP=Unity
XDG_SESSION_TYPE=x11
GNOME_KEYRING_PID=
QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
TERM=xterm
os x 动态连接器
DYLD_PRNT_FILE=/etc/sudoers
sudo bob
如果写入 bob ALL=(ALL)NOPASSED:ALL
该字段修改了root保护的/etc/sudoers 文件,导致的结果是bob可以用sudo 指令以root身份运行任何指令,实际上给bob用户root权限
减小攻击面
与system()相比,execve()的攻击面更小
execve()不调用shell,因此不受环境变量的影响
在特权程序中调用外部程序时,应该使用execve()
通过程序库攻击
案例研究—UNIX中的区域设置
每次需要打印出消息时,程序都会使用所提供的库函数来处理已翻译的消息
Unix使用libc库中的gettext()和catopen()
通过代码本身的代码进行攻击
#include <stdio.h>
#include <stdlib.h>
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;
}
unix 中常见的api 包括 getenv(),setenv(),putenv()
上述程序时获取pwd环境变量信息
problems
What is the difference between environment variables and shell variables?
shell变量是shell的特定实例(例如shell脚本)的局部变量,而环境变量是由启动的任何程序(包括另一个shell)
In Bash, if we run "export foo=bar", does it change the environment variable of the current process?
不会,只要在程序启动的时候,环境变量才会受影响