PHP内核分析FPM和disable_function安全问题

2019-07-0515:27:33WEB安全防护Comments2,965 views字数 12535阅读模式

今年的TCTF中,出现了攻击FPM绕过沙盒的场景。决定探究下FPM生命周期和disable_function源码实现,phpinfo不能准确显示。还很多地方还不熟悉,后面再慢慢补充,膜拜RR和P总,ORZ。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

调试环境

安装调试工具gdb文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

apt install gdb文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

下载php源码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

wget https://www.php.net/distributions/php-7.1.0.tar.gz文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

然后对./configure 的配置如下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

./configure  --prefix=/root/php7.1.0 --enable-phpdbg-debug --enable-debug --enable-fpm CFLAGS="-g3 -gdwarf-4"文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

查看Makefile文件如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CC = gcc文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CFLAGS = $(CFLAGS_CLEAN) -prefer-non-pic -static文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CFLAGS_CLEAN = -I/usr/include -g3 -gdwarf-4 -fvisibility=hidden -O0 -Wall -DZEND_SIGNALS $(PROF_FLAGS)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CPP = gcc -E文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CPPFLAGS =文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CXX =文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CXXFLAGS = -g -O0 -prefer-non-pic -static $(PROF_FLAGS)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CXXFLAGS_CLEAN = -g -O0文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

DEBUG_CFLAGS = -Wall文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

这里只安装必要的debug模块+fpm模块,其他模块视需求安装。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CFLAGS="-g3 -gdwarf-4"是对编译参数进行额外配置,关闭所有的编译优化机制,产生 gdb所必要的符号信息(符号表),并设置dwarf调试信息格式。PHP内核中定义了很多宏,gdb调试中可以通过macro expand xxxx命令比较方便的展开宏。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

编译安装php文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

件如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

make && make install文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

bin目录下包含常用的php命令行解释器文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

sbin目录下包含fpm,还需要运行的配置文件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

  • 指定fpm的配置文件,从编译后的目录复制php-fpm.conf.default并重命名为php-fpm.conf
  • 指定php的配置文件,从源码目录中复制php.ini-development并重命名为php.ini

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

自行配置php.ini,这里主要配置php-fpm.conf文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php-fpm为多进程模型,一个master进程,多个worker进程。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

master进程负责管理调度,worker进程负责处理客户端(nginx)的请求。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

master进程对work进程管理一共有三种模式:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

  • ondemand,按需模式,当有请求时才会启动worker
  • static,静态模式,启动采用固定大小数量的worker
  • dynamic,动态模式,初始化一些worker,运行过程中动态调整worker数量

让fpm的工作模式为static,并且work进程只有一个,方便进行调试,设置配置文件如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

pm = static文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; The number of child processes to be created when pm is set to 'static' and the文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; This value sets the limit on the number of simultaneous requests that will be文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; CGI. The below defaults are based on a server without much resources. Don't文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; forget to tweak pm.* to fit your needs.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: This value is mandatory.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

pm.max_children = 1文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; The number of child processes created on startup.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Used only when pm is set to 'dynamic'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

pm.start_servers = 1文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; The desired minimum number of idle server processes.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Used only when pm is set to 'dynamic'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Mandatory when pm is set to 'dynamic'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

pm.min_spare_servers = 1文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; The desired maximum number of idle server processes.文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Used only when pm is set to 'dynamic'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

; Note: Mandatory when pm is set to 'dynamic'文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

pm.max_spare_servers = 1文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

运行fpm文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

./php-fpm -c php.ini -y php-fpm.conf文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ps可以发现work进程如期只启动一个:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

fastcgi和FPM

浏览器请求Web Server上的html静态资源时,相互是通过Http协议进行通信,Web Server直接返回结果。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

当请求的资源为php等动态脚本资源时,Web Server根据配置会将请求文件交给后面的php解释器进行处理,然后返回处理结果给客户端。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

Web Server和PHP解释器之间通过CGI/FastCGI协议进行通信,流程如图所示:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

几者之间的关系:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

  • Cgi,通信协议,是Web Server 与 后端解释器之间数据交换的方式,但性能较差
  • FastCgi,通信协议,FastCGI是早期通用网关接口(CGI)的增强版本,一种语言无关的协议,性能的更强
  • PHP-CGI,PHP的CGI程序,接受来自web server的cgi/FastCgi通信数据,并使用php解释并返回结果,但性能较差
  • PHP-FPM,PHP-CGI的管理调度程序,包含PHP的CGI程序,能对php进行解释,接受来自web server的cgi/FastCgi通信数据,性能更强
SAPL--Cli和FPM

PHP文件需要解释器才能执行,需要运行在不同的环境下,比如命令行,Web等,因此使用不同的SAPI对解释器进行封装,为内部的PHP提供一套固定统一的接口, 使得PHP自身实现能够不受外部环境影响,保持一定的独立性,完成对各类环境的适配。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

常用的就是命令行的CLI-SAPI,Web的FPM-SAPI,SAPI目录结构如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

在不同的SAPI中,有着不同但相似的生命周期,对比分析一下CLI-SAPI,FPM-SAPI文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

Cli生命周期

cli的整个生命周期可以大致分为五个步骤文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

在cli模式下,每次脚本执行都会完整经历5个步骤。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

FPM生命周期

FPM的整个生命周期相对于cli更细化也有一定的变化文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

在FPM中模块初始化阶段仅在启动时运行一次,其他步骤会多次执行,循环处理每个FastCgi请求。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_disable_functions

php中对于php.ini中设置的disable_functions禁用函数列表的处理在php_module_startup阶段中的php_disable_functions函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

static void php_disable_functions(void)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *s = NULL, *e;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!*(INI_STR("disable_functions"))) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

e = PG(disable_functions) = strdup(INI_STR("disable_functions"));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (e == NULL) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

while (*e) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

switch (*e) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

case ' ':文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

case ',':文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (s) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

*e = '\0';文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_disable_function(s, e-s);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

s = NULL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

break;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

default:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!s) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

s = e;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

break;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

e++;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (s) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_disable_function(s, e-s);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

首先通过INI_STR("disable_functions")这个宏获取disable_functions的字符串,如果没有设置则返回文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

#define INI_STR(name) zend_ini_string_ex((name), sizeof(name)-1, 0, NULL)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

跟进zend_ini_string_ex文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API char *zend_ini_string_ex(char *name, uint name_length, int orig, zend_bool *exists) /* {{{ */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_ini_entry *ini_entry;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (ini_entry) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (exists) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

*exists = 1;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (orig && ini_entry->modified) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : NULL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return ini_entry->value ? ZSTR_VAL(ini_entry->value) : NULL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (exists) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

*exists = 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

    return NULL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

这里有个关键宏EG(ini_directives),可以访问全局变量executor_globals中的成员文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

# define EG(v) (executor_globals.v)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

extern ZEND_API zend_executor_globals executor_globals;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

executor_globals是一个zend_executor_globals类型的结构体,executor_globals.ini_directives是存放着php.ini信息的HashTable类型成员。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HashTable *ini_directives;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

通过zend_hash_str_find_ptr函数从EG(ini_directives)中获取disable_functions并返回。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

如果定义了disable_functions,通过while循环读取,swtich分割函数名,将禁用函数名传入zend_disable_function函数文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_internal_function *func;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

func->num_args = 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

func->arg_info = NULL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

func->handler = ZEND_FN(display_disabled_function);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return SUCCESS;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return FAILURE;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CG(function_table)也是一个重要的宏,可以访问全局变量compiler_globals中的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

compiler_globals.function_table是存放函数信息的HashTable文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HashTable *function_table;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

通过zend_hash_str_find_ptr函数从CG(function_table)中根据function_name获取函数指针,然后直接修改func->handler = ZEND_FN(display_disabled_function);,如果传入的function_name不是函数,不在函数表中就不操作直接返回。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API ZEND_FUNCTION(display_disabled_function)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name());文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

每次调用禁用函数的时候都会进入这里。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

phpinfo

phpinfo一直是查看服务器php信息的可靠方式,但是在包含修改disable_function的参数攻击FPM后,phpinfo已经显示修改,但是测试函数仍然禁用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP_FUNCTION(phpinfo)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_long flag = PHP_INFO_ALL;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flag) == FAILURE) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

/* Andale!  Andale!  Yee-Hah! */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_output_start_default();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_print_info((int)flag);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_output_end();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

RETURN_TRUE;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

进入php_print_info函数,只保留关键部分:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHPAPI void php_print_info(int flag)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_ini_sort_entries();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (flag & PHP_INFO_CONFIGURATION) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_hr();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!sapi_module.phpinfo_as_text) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print("文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

Configuration

    • \n");

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

SECTION("Configuration");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!(flag & PHP_INFO_MODULES)) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

SECTION("PHP Core");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

display_ini_entries(NULL);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (flag & PHP_INFO_MODULES) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HashTable sorted_registry;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_init(&sorted_registry, zend_hash_num_elements(&module_registry), NULL, NULL, 1);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_copy(&sorted_registry, &module_registry, NULL);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_sort(&sorted_registry, module_name_cmp, 0);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_apply(&sorted_registry, _display_module_info_func);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

/* }}} */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

sapi_module.phpinfo_as_text在FPM下为0,会调用php_info_print这类封装的输出函数输出带html标签的信息,然后在zend_hash_apply函数中继续调用传入的_display_module_info_func函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

uint32_t idx;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

Bucket *p;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int result;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

IS_CONSISTENT(ht);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HASH_PROTECT_RECURSION(ht);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

for (idx = 0; idx < ht->nNumUsed; idx++) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

p = ht->arData + idx;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

result = apply_func(&p->val);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

_display_module_info_func函数如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

static int _display_module_info_func(zval *el) /* {{{ */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_module_entry *module = (zend_module_entry*)Z_PTR_P(el);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (module->info_func || module->version) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_module(module);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return ZEND_HASH_APPLY_KEEP;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

将(zend_module_entry*)类型的module变量传入php_info_print_module函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHPAPI void php_info_print_module(zend_module_entry *zend_module) /* {{{ */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (zend_module->info_func || zend_module->version) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!sapi_module.phpinfo_as_text) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_string *url_name = php_url_encode(zend_module->name, strlen(zend_module->name));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_strtolower(ZSTR_VAL(url_name), ZSTR_LEN(url_name));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_printf("文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

%s

    • \n", ZSTR_VAL(url_name), zend_module->name);

efree(url_name);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_start();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_header(1, zend_module->name);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_end();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (zend_module->info_func) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_module->info_func(zend_module);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//.........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

此时的zend_module是cgi-fcgi文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

cgi-fcgi是phpinfo中的第一个module,disable_functions在Core中文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

放行至正确的Core,对应zend_module如下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

然后调用zend_module->info_func(zend_module),也就是进入zm_info_php_core函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP_MINFO_FUNCTION(php_core) { /* {{{ */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_start();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_row(2, "PHP Version", PHP_VERSION);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_end();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

DISPLAY_INI_ENTRIES();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP_MINFO_FUNCTION(php_core)也是一个宏,展开就是zm_info_php_core文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

进入DISPLAY_INI_ENTRIES()展开后的display_ini_entries(zend_module)函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHPAPI void display_ini_entries(zend_module_entry *module)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int module_number, module_number_available;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (module) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

module_number = module->module_number;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

module_number = 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

module_number_available = module_number;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_apply_with_argument(EG(ini_directives), php_ini_available, &module_number_available);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (module_number_available == -1) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_start();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_header(3, "Directive", "Local Value", "Master Value");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_hash_apply_with_argument(EG(ini_directives), php_ini_displayer, (void *)&module_number);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_info_print_table_end();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

module_number_available == -1条件满足,进入zend_hash_apply_with_argument(EG(ini_directives), php_ini_displayer, (void *)&module_number);函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

uint32_t idx;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

Bucket *p;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int result;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

IS_CONSISTENT(ht);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HASH_PROTECT_RECURSION(ht);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

for (idx = 0; idx < ht->nNumUsed; idx++) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

p = ht->arData + idx;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

result = apply_func(&p->val, argument);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (result & ZEND_HASH_APPLY_REMOVE) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HT_ASSERT(GC_REFCOUNT(ht) == 1);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

_zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (result & ZEND_HASH_APPLY_STOP) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

break;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

HASH_UNPROTECT_RECURSION(ht);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

从EG(ini_directives)中获取(zend_ini_entry*)类型的配置参数结构成员,在for循环中遍历并作为参数传入result = apply_func(&p->val, argument),实际进入php_ini_displayer函数,继续跟进:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

static int php_ini_displayer(zval *el, void *arg)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int module_number = *(int *)arg;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (ini_entry->module_number != module_number) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (!sapi_module.phpinfo_as_text) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("\n");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS(" => ");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS(" => ");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PUTS("\n");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

进入if (!sapi_module.phpinfo_as_text)分支后就是每项配置的输出,php_ini_displayer_cb是封装的输出函数,大致顺序就是这样,具体调用栈如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

phpinfo根据EG(ini_directives)中获取信息并打印。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

攻击PHP-FPM分析

跟踪PHP-FPM接受恶意的FastCgi协议并解析根据PHP_VALUE设置disable_functions=。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

fcgi_accept_request函数中通过accept函数接受来自客户端的socket连接,并赋给req->fd。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

会通过外层while循环不停地接受连接文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

同时将包含请求句柄的request变量存到全局变量,SG(server_context)中,宏定义如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

# define SG(v) (sapi_globals.v)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

extern SAPI_API sapi_globals_struct sapi_globals;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

然后进入init_request_info函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

static void init_request_info(void)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

fcgi_request *request = (fcgi_request*) SG(server_context);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *env_script_filename = FCGI_GETENV(request, "SCRIPT_FILENAME");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *env_path_translated = FCGI_GETENV(request, "PATH_TRANSLATED");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *script_path_translated = env_script_filename;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *ini;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int apache_was_here = 0;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//..........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//..........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

//..........文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

/* INI stuff */文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini = FCGI_GETENV(request, "PHP_VALUE");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (ini) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int mode = ZEND_INI_USER;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *tmp;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

spprintf(&tmp, 0, "%s\n", ini);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

efree(tmp);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini = FCGI_GETENV(request, "PHP_ADMIN_VALUE");文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (ini) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int mode = ZEND_INI_SYSTEM;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

char *tmp;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

spprintf(&tmp, 0, "%s\n", ini);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

efree(tmp);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

通过FCGI_GETENV宏获取FastCgi请求中的PHP_VALUE:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

fcgi_quick_getenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1))文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

接着进入zend_parse_ini_string函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

int retval;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

zend_ini_parser_param ini_parser_param;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini_parser_param.ini_parser_cb = ini_parser_cb;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini_parser_param.arg = arg;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CG(ini_parser_param) = &ini_parser_param;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (zend_ini_prepare_string_for_scanning(str, scanner_mode) == FAILURE) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return FAILURE;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

CG(ini_parser_unbuffered_errors) = unbuffered_errors;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

retval = ini_parse();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

shutdown_ini_scanner();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

if (retval == 0) {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return SUCCESS;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

} else {文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

return FAILURE;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

ini_parser_param.ini_parser_cb = ini_parser_cb实赋值的fastcgi_ini_parser函数,然后进入ini_parse进行解析,然后又使用了ZEND_INI_PARSER_CB宏文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

查看定义:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

#define ZEND_INI_PARSER_CB  (CG(ini_parser_param))->ini_parser_cb文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

实际调用fastcgi_ini_parser函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

继续进入fpm_php_apply_defines_ex函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

此时的调用信息如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

继续进入fpm_php_zend_ini_alter_master函数文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

这里从EG(ini_directives)找到表示disable_functions的ini_entry,然后修改值为我们传入的内容,而phpinfo展示的值就源于这里。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

还会将要禁用的函数字符串传入fpm_php_disable函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

PHP内核分析FPM和disable_function安全问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

再调用zend_disable_function函数修改func->handler完成禁用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html

总结
  • 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。
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/anquan/13979.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/anquan/13979.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定