Skip to content

Commit

Permalink
update: php document
Browse files Browse the repository at this point in the history
  • Loading branch information
LyleMi committed Jul 15, 2019
1 parent a00ac26 commit 38f24cd
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 16 deletions.
54 changes: 54 additions & 0 deletions source/language/php/basedir.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Open Basedir
================================

机制实现
---------------------------------
PHP中Disable Function的实现是在php-src/main/fopen-wrappers.c中,实现方式是在调用文件等相关操作时调用函数根据路径来检查是否在basedir内,其中一部分实现代码如下:

.. code:: c
PHPAPI int php_check_open_basedir_ex(const char *path, int warn)
{
/* Only check when open_basedir is available */
if (PG(open_basedir) && *PG(open_basedir)) {
char *pathbuf;
char *ptr;
char *end;
/* Check if the path is too long so we can give a more useful error
* message. */
if (strlen(path) > (MAXPATHLEN - 1)) {
php_error_docref(NULL, E_WARNING, "File name is longer than the maximum allowed path length on this platform (%d): %s", MAXPATHLEN, path);
errno = EINVAL;
return -1;
}
pathbuf = estrdup(PG(open_basedir));
ptr = pathbuf;
while (ptr && *ptr) {
end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
if (end != NULL) {
*end = '\0';
end++;
}
if (php_check_specific_open_basedir(ptr, path) == 0) {
efree(pathbuf);
return 0;
}
ptr = end;
}
if (warn) {
php_error_docref(NULL, E_WARNING, "open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s)", path, PG(open_basedir));
}
efree(pathbuf);
errno = EPERM; /* we deny permission to open it */
return -1;
}
/* Nothing to check... */
return 0;
}
57 changes: 57 additions & 0 deletions source/language/php/disablefunc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Disable Functions
================================

机制实现
---------------------------------
PHP中Disable Function的实现是在php-src/Zend/Zend-API.c中。PHP在启动时,读取配置文件中禁止的函数,逐一根据禁止的函数名调用 ``zend_disable_function`` 来实现禁止的效果。

这个函数根据函数名在内置函数列表中找到对应的位置并修改掉,当前版本的代码如下:

.. code:: c
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:: c
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
- PHP OPcache
- Mail函数
- imap_open
- https://www.cvedetails.com/cve/cve-2018-19518
2 changes: 2 additions & 0 deletions source/language/php/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ PHP

backdoor
unserialize
disablefunc
basedir
phpinfo
htaccess
webshell
Expand Down
11 changes: 0 additions & 11 deletions source/language/php/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ PHP字符存在截断行为,可以使用 ``ereg`` / ``%00`` / ``iconv`` 等实
- system
- proc_open


Disable Functions Bypass
---------------------------------
- LD_PRELOAD绕过
- https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
- PHP OPcache
- Mail函数
- imap_open
- https://www.cvedetails.com/cve/cve-2018-19518


Magic函数
---------------------------------
- ``__construct()`` ``__destruct()``
Expand Down
18 changes: 13 additions & 5 deletions source/language/php/unserialize.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
反序列化
================================

PHP序列化格式
PHP序列化实现
--------------------------------
PHP序列化处理共有三种,分别为php_serialize、php_binary和 WDDX,默认为php_serialize,可通过配置中的 ``session.serialize_handler`` 修改。

其中php_serialize的实现在 ``php-src/ext/standard/var.c`` 中,主要函数为 ``php_var_serialize_intern`` ,序列化后的格式如下:

- boolean
- ``b:<value>;``
Expand All @@ -22,6 +25,11 @@ PHP序列化格式
- ``a:1:{s:4:"key1";s:6:"value1";}`` // ``array("key1" => "value1");``
- object
- ``O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>};``
- reference
- 指针类型
- ``R:reference;``
- ``O:1:"A":2:{s:1:"a";i:1;s:1:"b";R:2;}``
- ``$a = new A();$a->a=1;$a->b=&$a->a;``

PHP反序列化漏洞
--------------------------------
Expand All @@ -34,7 +42,7 @@ php在反序列化的时候会调用 ``__wakeup`` / ``__sleep`` 等函数,可

下面提供一个简单的demo.

::
.. code:: php
class Demo
{
Expand Down Expand Up @@ -91,7 +99,7 @@ php在反序列化的时候会调用 ``__wakeup`` / ``__sleep`` 等函数,可
那么,在 ``__wakeup()`` 中加入判断是否可以阻止这个漏洞呢?
在 ``__wakeup()`` 中我们加入一行代码

::
.. code:: php
public function __wakeup()
{
Expand All @@ -103,7 +111,7 @@ php在反序列化的时候会调用 ``__wakeup`` / ``__sleep`` 等函数,可

::

unserialize('O:7:"HITCON":1:{s:4:"data";s:15:"malicious value";}');
unserialize('O:7:"HITCON":1:{s:4:"data";s:15:"malicious value";}');

输出

Expand All @@ -112,4 +120,4 @@ unserialize('O:7:"HITCON":1:{s:4:"data";s:15:"malicious value";}');
Data's value is malicious value.
destruct

这里wakeup被绕过,值依旧被修改了。
这里wakeup被绕过,值依旧被修改了。

0 comments on commit 38f24cd

Please sign in to comment.