Содержание статьи
В стремлении увеличить производительность PHP-приложений разработчики нередко прибегают к использованию альтернативных реализаций интерпретатора. За счет хитрых оптимизаций такие решения действительно позволяют увеличить производительность в разы, но при этом таят в себе дополнительные опасности.
В чем смысл?
Существует сразу несколько сторонних реализаций PHP. Все они создавались с целью повышения производительности, а также расширения возможностей языка. При использовании сторонних реализаций PHP скорость работы приложений в среднем возрастает до пяти раз — показатель, несомненно, высокий. Достигается это благодаря использованию кросскомпиляции. В общем виде процесс компиляции осуществляется в два шага:
- PHP-сценарий транслируется в промежуточный код (как правило, это C-код);
- C-код компилируется в машинный.
Наиболее популярными и распространенными среди альтернативных реализаций PHP являются Roadsend PHP, Phalanger, Quercus on Resin, а также HipHop for PHP. Сначала я кратко расскажу о каждой из них, а потом приступим к самому интересному — проверим их на предмет безопасности.
Альтернативные реализации PHP
Roadsend PHP
Реализация Roadsend PHP состоит, по сути, из двух компонентов — компилятора и интегрированного веб-сервера, называемого MicroServer. Компиляция осуществляется с промежуточным транслированием PHP-кода в код на языке С. Встроенный веб-сервер позволяет запускать полученные в результате компиляции приложения без использования каких-либо дополнений и ухищрений. В случае если необходимо использовать привычный веб-сервер вроде Apache, lighttpd, nginx, то скомпилированное приложение придется связывать с веб-сервером посредством интерфейса CGI или FastCGI.
Phalanger
Phalanger представляет больший интерес для многих разработчиков, так как помимо лучшей, по сравнению с оригинальным PHP, производительностью, предоставляет и дополнительные возможности. Он позволяет обращаться PHP-приложениям почти ко всем .NET-конструкциям, благодаря чему можно создавать более гибкие веб-приложения, синтаксис которых не ограничивается одним PHP. Phalanger работает с веб-сервером IIS, и процесс их интеграции не сложнее, чем в случае с оригинальным PHP.
Quercus on Resin
Еще один пример стыка технологий — веб-сервер Resin. В первых версиях Resin представлял собой веб-сервер и сервер приложений для Java, но затем появилась реализация PHP, называемая Quercus. Resin имеет две ветки — Professional и Open Source. В версии Professional PHP-код компилируется в байт-код Java, в то время как в Open Source версии PHP-код интерпретируется.
HipHop for PHP
Последняя из рассмотренных реализаций — HipHop, разработчиком которой является компания Facebook. HipHop транслирует PHP-сценарии в промежуточный код на C++, а затем, используя компилятор g++, создает исполняемый файл. Следует отметить, что размер даже примитивного приложения, скомпилированного при помощи HipHop, достигает около 30 мегабайт. Но при этом приложение уже включает в себя веб-сервер: достаточно при запуске указать соответствующий ключ и порт, по которому приложение должно быть доступно. Помимо этого, как и в случае с Roadsend PHP, полученные приложения могут связываться с веб-серверами с помощью интерфейсов CGI или FastCGI. Компиляция занимает длительное время, и если в приложение постоянно вносятся изменения, то процесс обновления может стать серьезной головной болью. Однако есть и сильная сторона — исключаются некоторые категории уязвимостей:
- Подключение произвольных файлов (Local File Inclusion) — подключать можно только те файлы, которые присутствовали на момент компиляции;
- Загрузка произвольных файлов — загруженные файлы исполняться не будут, так как исполняемыми они не являются, а интерпретатор здесь не используется.
Подход к исследованию
Итак, перед нами стоит задача выявить проблемы безопасности сразу нескольких новых языков, синтаксис которых совпадает с PHP. Будет ли совпадать результат, особенности и поведение? А главное — насколько безопасно использование сторонних реализаций?
Сразу же возникает вопрос, как сравнить и на что нужно смотреть. Резонно выделить категории, по которым можно будет проверить каждую из реализаций:
- уязвимости окружения — почти все реализации содержат собственные веб-серверы и прочее окружение, являющееся неотъемлемой частью веб-приложения;
- механизмы обработки параметров, тут следует вспомнить атаки HTTP Parameter Pollution и HTTP Parameter Contamination, а также уделить внимание глобализации и типизации переменных;
- уязвимости стыка технологий — новые возможности могут повлечь за собой и новые уязвимости;
- уязвимости, которые встречались в очень старых версиях оригинального PHP.
Уязвимости окружения
Здесь отличился Roadsend PHP, а точнее, входящий в него веб-сервер MicroServer. Выяснилось, что он уязвим к очень простому варианту уязвимости Path Traversal. Пример эксплуатации приведен в листинге.
Эксплуатация Path Traversal в Roadsend PHP
http://host/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
Как видно из запроса, тут все просто — используются переходы к родительскому каталогу, а к символу слеша при этом применяется URL-кодирование. В результате можно получить контент любого файла (см. рис. 1). Но в данном случае можно эксплуатировать проще — указывая абсолютный путь до файла:
Эксплуатация Path Traversal
http://host//etc/passwd
Проект Roadsend PHP с недавнего времени не поддерживается, хотя ресурсы, использующие его, еще остались. Владельцам этих ресурсов следует подобрать другое решение.
Хакер #163. Лучшие гаджеты для хакера
Обработка параметров
Как известно, различные платформы и приложения по-разному обрабатывают заведомо некорректные символы и конструкции: в каких-то случаях такие символы заменяются, а в каких-то случаях такая замена не осуществляется. На этом и основана атака HTTP Parameter Contamination. Обычно она используется с целью обхода различных фильтраций, а также для формирования специфических векторов client-side атак. В табл. 1 приведены расхождения в обработке некорректных символов для различных реализаций PHP — за эталон принят обычный LAMP. Как видно, результат отличается от оригинального PHP. Причем расхождения получились почти идентичными для Phalanger и Quercus. И помимо возможности создавать переменные, именем которых является пустая строка, в обоих случаях можно добиться вывода ошибки 500 (см. забавный fingerprint на рис. 2).
Возможность создавать переменные, содержащие в имени символ пробела и тем более null-byte, скажется в некорректной работе приложения при циклических обходах массивов (см. листинг), когда используется не только значение переменной, но и ее имя.
Циклический обход массива, уязвимость Local File Inclusion
foreach($_GET["language"] as $langDir => $langFile) {
include($langDir."/".$langFile.".php");
}
В приведенном коде имя переменной передается в конструкцию, подключающую сценарии. Используя null-byte в имени переменной, можно отбросить часть строки и таким образом подключить произвольный файл.
Подключение файла /etc/passwd
http://host/index.php?language["/etc/passwd%00"]=1
Глобализация и перезапись переменных
Возможность задавать значения переменных напрямую — брешь в безопасности веб-приложений. В оригинальном PHP за подобное поведение отвечает опция register_globals, причем начиная с версии 5.4.0 она удалена. Логично предположить, что в сторонних реализациях PHP не все так гладко, как хотелось бы. В Quercus опция register_globals отсутствует (сами разработчики называют ее «черной дырой в безопасности»), однако при передаче параметров методом POST происходит их глобализация, а при заявленном отсутствии опции этого быть не должно. Но это не главная проблема — гораздо опаснее то, что параметры, переданные методом POST, могут перезаписывать элементы массива _SERVER. На рис. 3 приведен пример перезаписи значения элемента_SERVER["REMOTE_ADDR"]
, что, по сути, приводит к подмене значения клиентского IP-адреса.
Наиболее опасный вектор атаки — подмена значения элемента $_SERVER["DOCUMENT_ROOT"]
, содержащего абсолютный путь до веб-каталога, и развитие атаки Local File Inclusion (см. рис. 4). Следует отметить, что даже безопасный для оригинального PHP код (см. листинг) становится уязвимым, если существует возможность перезаписи переменных.
Использование $_SERVER["DOCUMENT_ROOT"] в коде
<?php
include($_SERVER["DOCUMENT_ROOT"]."header.php");
?>
Описание уязвимости приведено в advisory: bit.ly/MFeJYu. Исправление уязвимости ожидается в новых версиях. Интересно то, что перезаписать элементы массива _SESSION не получится: попытка перезаписи заканчивается сообщением об ошибке. Оно и к лучшему, так как иначе любой механизм авторизации, использующий массив _SESSION, становился бы уязвимым.
Типизация переменных
В PHP существует так называемое гибкое сравнение, позволяющее сравнивать переменные различного типа (при тождественном сравнении переменных различного типа его результат всегда будет false). Сравнение происходит с некоторыми особенностями, они сведены в таблицу на официальном сайте PHP. Несоблюдение данных особенностей может привести к непредсказуемой работе приложения. Расхождения с оригинальным PHP нашлись достаточно быстро. В сценариях, приведенных в листинге, осуществляется сравнение пустого массива с переменными различного типа.
Гибкое сравнение переменных различного типа
// script 1
<?php
$xArray = array(TRUE, FALSE, 1, 0, -1, "1", "0", "-1", NULL, array(), "php", "");
foreach($xArray as $x) {
if($x == array()) { echo("TRUE"); } else { echo("FALSE"); }
echo("<br>");
}
?>
// script 2
<?php
$xArray = array(TRUE, FALSE, 1, 0, -1, "1", "0", "-1", NULL, array(), "php", "");
foreach($xArray as $x) {
if(array() == $x) { echo("TRUE"); } else { echo("FALSE"); }
echo("<br>");
}
?>
Различаются сценарии порядком следования сравниваемых переменных, но, по сути, они идентичны. Соответственно, результаты сравнения также должны совпадать. Но, как видно из табл. 3, в Quercus результат сравнения зависит от порядка следования сравниваемых переменных, что является нетипичным поведением для PHP. Кроме этого, результат сравнения пустого массива array() и 0 является истиной, что также не типично для оригинального PHP. Это может привести к обходу различных проверок, например в механизмах аутентификации или авторизации.
Уязвимости стыка технологий
Как известно, в PHP существует возможность устанавливать различные ограничения безопасности. Например, можно использовать опцию disable_functions, запрещающую вызывать указанные функции (как правило, это функции, выполняющие shell-команды), или опцию open_basedir, ограничивающую доступ к файловой системе. Но обычно возможность использования сторонних конструкций не учитывается.
Использование опции disable_functions для запрета выполнения shell-команд
disable_functions: system, exec, shell_exec, passthru, popen, proc_open, pcntl_exec
Таким образом, используя для выполнения shell-команд конструкции .NET, можно обходить заданное ограничение безопасности. Пример обхода приведен в листинге.
Выполнение shell-команд через конструкции .NET
<?php
$process = new Diagnostics\Process();
$process->StartInfo->FileName = "cmd.exe";
$process->StartInfo->WorkingDirectory = "C:\\";
$process->StartInfo->Arguments = "/c ".$_GET["cmd"];
$process->Start();
$process->WaitForExit();
?>
Old School
- Межсайтовое выполнение сценариев в сообщениях об ошибках
Отличились Roadsend PHP и Quercus — в сообщениях об ошибках служебные символы не заменяются на их HTML-эквиваленты, в результате чего возможно проведение атак на пользователей сайта (см. рис. 5). Видимо, разработчики забыли, что на дворе 2012 год, а не 2002-й?
- Path Traversal в имени загружаемого файла
Quercus, входящий в состав 3-й ветки веб-сервера Resin, уязвим к Path Traversal в механизме загрузки файлов на сервер. Переходы к родительскому каталогу не удаляются из имени файла. В результате можно загружать файлы в произвольный каталог — пример запроса приведен в листинге.
Пример HTTP-запроса, загружающего файл в родительский каталог
POST http://127.0.0.1:8080/test/file.php HTTP/1.1
…
Content-Type: multipart/form-data;
boundary=---------------------------101412320927450
Content-Length: 228
-----------------------------101412320927450
Content-Disposition: form-data; name="test";
filename="../shell.php"
Content-Type: application/octet-stream
<?php
phpinfo();
?>
-----------------------------101412320927450--
Описание уязвимости приведено в advisory: bit.ly/MFeJYu. Исправление уязвимости ожидается в новых версиях.
- Null-byte в имени загружаемого файла
Path Traversal не единственная проблема при загрузке файлов в Quercus. Еще одна не менее опасная проблема — возможность передачи в имени файла null-byte, что позволяет отбросить принудительно добавляемый к имени загружаемого файла постфикс (например, расширение jpg), а также обходить ряд проверок безопасности. Пример проверки, которую можно обойти, приведен в следующем листинге.
Пример проверки расширения файла
<?php
if(isset($_FILES["image"])) {
if(!preg_match('#\.(jpg|png|gif)$#', $_FILES["image"]["name"])) {
die("Hacking attempt!");}
copy($_FILES["image"]["tmp_name"],
"./uploads/".$_FILES["image"]["name"]
);
}
?>
В приведенном сценарии осуществляется проверка расширения файла: оно должно быть одним из допустимых (jpg, png или gif), и если это не так, то файл загружен не будет. Сама по себе проверка более чем адекватная, но при возможности использования null-byte в имени файла обойти такую проверку труда не составит — достаточно передать в имени файла null-byte, а затем .jpg. Таким образом проверка будет пройдена, а в момент копирования файла строка .jpg будет отброшена. Исправление уязвимости ожидается в новых версиях.
Positive Hack Days 2012
Данная статья основана на выступлении Сергея Щербеля на международном форуме по практической безопасности Positive Hack Days 2012. Напомню, PHDays — это международный форум, посвященный вопросам практической информационной безопасности. Своим появлением PHDays поставил точку в разговорах хакерской тусовки, посвященных идеям на тему «Как было бы круто иметь свой DEF CON или Black Hat в России». Мы получили оба в одной бутылке :). PHDays — это место, где футболки встречаются с пиджаками, а парни с Античата обсуждают результаты взлома интернет-банка с топ-менеджером из финансовых структур. Презентация, по мотивам который подготовлен этот материал, доступна по адресу slidesha.re/Nl2VLF. Получить информацию о самом мероприятии, а также посмотреть список доступных материалов ты можешь на официальном сайте этой уникальной хакерской конференции (www.phdays.ru).
Подводим итоги
Все рассмотренные реализации PHP имеют значительное преимущество в производительности (прирост до пяти раз, что очень недурно), но при этом почти у всех есть проблемы безопасности:
- уязвимое окружение;
- проблемы с обработкой параметров (глобализация и типизация);
- различные нарушения логики;
- Path Traversal в различных проявлениях и другие.
Из-за указанных уязвимостей даже безопасное веб-приложение становится уязвимым при использовании сторонних реализаций PHP. Яркий пример — реализация Quercus, которая оказалась самой уязвимой из рассмотренных. Хотя есть и исключение: HipHop в чем-то даже безопаснее оригинального PHP.