【发布时间】:2019-11-20 12:17:13
【问题描述】:
存在一种称为phardeserialisation 的(相当新的)利用技术,它由PHP 的file system functions 触发,例如file_exists,unlink,...然后非序列化代码在实例化类中执行需要至少包含__wakeup 和__destruct 两个魔术方法之一。
我的想法是在 PHP 的源代码中搜索内置 PHP 类,这些类可能具有本机实现的魔术方法(__wakeup 和 __destruct)作为此类类的一部分,并且可以在反序列化过程中以某种方式被利用 异常处理(可能会触发一些释放后使用的错误)。事实上,我在几个 Exception 类中找到了__wakeup(获取所有内置类并检查它们是否具有__wakeup 和__destruct 方法的简单方法是使用PHP 函数get_declared_classes())。但目前看来,它似乎无法利用。
所以问题不在于利用事物。
问题:我不明白为什么,例如__wakeup 在异常中实现?它只是扩展此类 Exception 类并在以后编写自己的__wakeup/__destruct 方法的占位符方法吗?
源代码: https://github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L316
在第 306-333 行(php-src/Zend/zend_exceptions.c,PHP 7.4):
/* }}} */
/* {{{ proto Exception::__wakeup()
Exception unserialize checks */
#define CHECK_EXC_TYPE(id, type) \
pvalue = zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &value); \
if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \
zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \
}
ZEND_METHOD(exception, __wakeup)
{
zval value, *pvalue;
zval *object = ZEND_THIS;
CHECK_EXC_TYPE(ZEND_STR_MESSAGE, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_STRING, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_CODE, IS_LONG);
CHECK_EXC_TYPE(ZEND_STR_FILE, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_LINE, IS_LONG);
CHECK_EXC_TYPE(ZEND_STR_TRACE, IS_ARRAY);
pvalue = zend_read_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1, 1, &value);
if (pvalue && Z_TYPE_P(pvalue) != IS_NULL && (Z_TYPE_P(pvalue) != IS_OBJECT ||
!instanceof_function(Z_OBJCE_P(pvalue), zend_ce_throwable) ||
pvalue == object)) {
zend_unset_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1);
}
}
/* }}} */
之后在第 788-801 行: https://github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L788
static const zend_function_entry default_exception_functions[] = {
ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, __toString, NULL, 0)
ZEND_FE_END
};
【问题讨论】:
标签: php c exception deserialization magic-methods