环境变量注入
假设拿到了一个shell但无法执行系统命令
这是一个空壳shell,可以通过上传LD_PRELOAD
进行绕过,怎么判断要覆写的函数名?
可以通过看sh会调用的库函数
1 | └─$ sudo readelf -Ws /usr/bin/sh |
挑一个geteuid
hacker.c
1 |
|
编译成.so文件,
就是将一系列的c函数打包到一个文件中,方便其他二进制文件调用,这样的文件就是so文件,也称动态链接库,相当于windows中的dll文件。
1 | gcc -shared -fPIC hacker.c -o hacker.so |
上传so文件到有写入权限的目录下,权限也很玄乎,假如shell写入权限不够就很难利用了,参考羊城杯2023的ez_web,上传目录居然是etc,也考倒了很多
写入临时webshell
1 |
|
访问临时webshell即可成功执行system命令
当然hacker.c也可以这样子写
1 |
|
临时webshelll
1 |
|
假如没有上传点也没有利用点该怎么触发命令执行
如下代码:
1 |
|
怎么触发命令执行?
php的system是调用的sh,在centos系统中sh指向bash,在p神的文章中也对比了dash的利用,虽然很鸡肋但是最后还是发现bash可以利用,是因为variables.c的initialize_shell_variables
函数用于将环境变量注册成SHELL的变量
1 | for (string_index = 0; env && (string = env[string_index++]); ) { |
这里for遍历了所有环境变量,并用=
分割,name
就是环境变量名,string
是值。
当满足下面这些条件的情况下,temp_string
将被传入parse_and_execute
执行:
-
privmode == 0
,即不能传入-p
参数 -
read_but_dont_execute == 0
,即不能传入-n
参数 -
STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN)
,环境变量名前10个字符等于BASH_FUNC_
-
STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN)
,环境变量名后两个字符等于%%
-
STREQN ("() {", string, 4)
,环境变量的值前4个字符等于() {
前两个条件肯定是满足的,后三个条件是用户可控的,所以这个if语句是肯定可以进入的。进入if语句后,去除前缀BASH_FUNC_
和后缀%%
的部分将是一个变量名,而由() {
开头的字符串将会被执行。
这里其实做的就是一件事:根据环境变量的值初始化一个匿名函数,并赋予其名字。
所以,我们传入下面这样一个环境变量,将会在Bash上下文中添加一个myfunc函数:
1 | env $'BASH_FUNC_myfunc%%=() { id; }' bash -c 'myfunc' |
centos8下poc为
1 | env $'BASH_FUNC_echo%%=() { id; }' bash -c 'echo hello' |
所以对于上面的php代码poc为
1 | ?envs[BASH_FUNC_echo%25%25]=()%20{%20id;%20} |
centos7(Bash 4.2
)poc为
1 | env $'BASH_FUNC_echo()=() { id; }' bash -c "echo hello" |
对于p神的总结遇到环境变量注入可以这样子尝试
1 | Bash没有修复ShellShock漏洞:直接使用ShellShock的POC进行测试,例如TEST=() { :; }; id; |
参考:
https://www.leavesongs.com/PENETRATION/how-I-hack-bash-through-environment-injection.html