Найти тему
Nuances of programming

Погружение в unserialize(): больше, чем RCE

Оглавление

Источник: Nuances of Programming

Обход аутентификации и внедрение SQL-кода через unserialize() в PHP

Сериализация в PHP через метод unserialize() приводит к появлению уязвимостей, открывающих через RCE (удаленное выполнение кода) доступ для хакеров. Даже при отсутствии RCE существует вероятность обхода системы аутентификации и внедрения SQL-кода.

Обход механизма аутентификации

Уязвимости unserialize() часто используются для обхода проверки безопасности приложения. Есть два способа реализации. Первый заключается в управлении свойствами объекта, чтобы получить контроль доступа. Второй способ  —  манипуляции с типами. Оба метода основаны на том, что конечный пользователь может управлять переданным в функцию объектом.

Управление свойствами объекта

Это один из самых простых и распространенных способов использования уязвимости десериализации для обхода аутентификации.

class User{
public $username = "vickie";
public $type = "Regular User";
# еще PHP код
}

Предположим, приложение использует класс User для передачи личной информации в процессе регистрации. После заполнения формы пользователем, эти данные будут сообщены во внутреннюю базу через сериализованный объект User.

Так как у конечного пользователя есть право на управление объектом User, он может изменить характеристики объекта и зарегистрироваться как пользователь с правами администратора.

class User{
public $username = "vickie";
public $type = "Admin User";
# еще немного PHP кода
}

Манипулирование типами переменных

Еще один простой способ взлома, основанный на функции манипуляции типами в PHP. В качестве примера рассмотрим код, используемый для входа в систему под именем администратора:

parse_str($_POST['user_password'], $password_array);
$pw = unserialize($password_array[0]);
if ($pw->password == "Admin_Password")
{login_as_admin();}

Хакер может отправить запрос POST, чтобы войти как админ:

class Password{
public $password = 0;
# и еще PHP код
}
# строка принята как тело POST:
print urlencode(serialize(new Password));

Это сработает, так как ответом на (0 == “Admin_Password”) будет true. При сравнении разных типов данных в PHP запускается процесс сведения их к одному типу. Следовательно, “Admin_Password” превратится в 0. И выражение станет эквивалентным (0 == 0).

SQL-инъекция

При определенных условиях уязвимости unserialize() могут быть использованы для внедрения SQL-кода.

Использование POP-цепочек

Предположим, где-то в коде приложение определяет класс Example3 и десериализует нефильтрованный пользовательский ввод из данных POST.

-2

__toString()  —  это магический метод, вызываемый каждый раз, когда класс рассматривается как строка. В таком случае Example3 обрабатывается как строка, и в результате метода getValue() возвращается свойство $obj.

Предположим, в приложении также определен класс SQL_Row_Value с методом getValue(), который выполняет SQL запрос. Запрос получает данные из свойства $_table экземпляра SQL_Row_Value.

-3

Хакер может внедрить SQL-код, используя $obj в Example3: нижеследующий код создаст экземпляр Example3 с $obj, где значение $_table в SQL_Row_Value будет определено как строка “SQL Injection”.

-4

Всякий раз, когда этот экземпляр обрабатывается как строка, вызывается метод get_Value() в $obj. То есть для SQL_Row_Value этот метод будет выполняться со строкой “SQL Injection”.

Таким образом, хакер реализовал ограниченное внедрение SQL-кода, поскольку он может контролировать строку, переданную в SQL запрос "SELECT * FROM {$this->_table} WHERE id = ". (int)$id;

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи Vickie Li: Diving into unserialize(): More than RCE