Существует (довольно новый) метод эксплуатации, называемый phar десериализация , который запускается функциями PHP * файловой системы , такими как file_exists
, unlink
,... и затем несериализованный код выполняется внутри экземпляра класса, который должен содержать хотя бы один из двух магических методов __wakeup
и __destruct
.
Моя идея заключалась в том, чтобы искать в исходном коде PHP встроенный PHPклассы, которые могут иметь такие магические методы, изначально реализованные (__wakeup
и __destruct
) как часть таких классов, и могут быть каким-то образом использованы в процессе десериализации во время обработки Exception (которая может вызывать, например, некоторое использование послебесплатные ошибки).Действительно, я обнаружил __wakeup
в нескольких Exception классах (простой способ получить все встроенные классы и проверить их на наличие методов __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
};