Disable Functions ================================ 机制实现 --------------------------------- PHP中Disable Function的实现是在php-src/Zend/Zend-API.c中。PHP在启动时,读取配置文件中禁止的函数,逐一根据禁止的函数名调用 ``zend_disable_function`` 来实现禁止的效果。 这个函数根据函数名在内置函数列表中找到对应的位置并修改掉,当前版本的代码如下: .. code-block:: cpp ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */ { zend_internal_function *func; if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) { zend_free_internal_arg_info(func); func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_RETURN_TYPE); func->num_args = 0; func->arg_info = NULL; func->handler = ZEND_FN(display_disabled_function); return SUCCESS; } return FAILURE; } 和函数的实现方式类似,disable classes也是这样实现的 .. code-block:: cpp ZEND_API int zend_disable_class(char *class_name, size_t class_name_length) /* {{{ */ { zend_class_entry *disabled_class; zend_string *key; key = zend_string_alloc(class_name_length, 0); zend_str_tolower_copy(ZSTR_VAL(key), class_name, class_name_length); disabled_class = zend_hash_find_ptr(CG(class_table), key); zend_string_release_ex(key, 0); if (!disabled_class) { return FAILURE; } INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new); disabled_class->create_object = display_disabled_class; zend_hash_clean(&disabled_class->function_table); return SUCCESS; } 因为这个实现机制的原因,在PHP启动后通过 ``ini_set`` 来修改 ``disable_functions`` 或 ``disable_classes`` 是无效的。 Bypass --------------------------------- - LD_PRELOAD绕过 - https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD - ``mail()`` + ``putenv`` - PHP OPcache - Mail函数 - imap_open - https://www.cvedetails.com/cve/cve-2018-19518