Было уже за полночь, когда в аську мне от старого знакомого прилетело
сообщение со ссылкой на один web-узел в интернете. В сообщении говорилось, что в
настоящее время проводятся работы по анализу защищенности этого ресурса. И если
у меня есть желание поучаствовать, то моя помощь была бы крайне полезна.

По указанной ссылке моему взору предстал симпатичный сайт с убогой
навигацией. Поглумившись немного над дизайном, исследования я начал по
стандартной схеме – с поиска наиболее опасных багов на стороне сервера. При
обращении к новостному разделу сразу же бросилось в глаза использование
mod_rewrite, который порой затрудняет эксплуатацию ряда наиболее интересных
server-side уязвимостей. Поверхностный серфинг по структуре сайта показал, что
никакими SQL-инъекциями и прочими вкусностями тут и не пахнет. Это лишь
подогревало интерес к поиску уязвимостей.

Продолжая исследование сайта, в HTML-коде различных его разделов я наткнулся
на интересную строку: content="eZ publish". Гугление по сигнатуре показало, что
ресурс, видимо, базируется на Open source CMS eZPublish. Через пару минут
предположение получило подтверждение. Стоило мне обратиться к странице
/ezinfo/about, сервер выплюнул точную версию CMS со всеми установленными
дополнениями. Это была eZPublish версии 3.9.3.

На офсайте разработчика этой CMS аккуратно собраны уязвимости под старые
версии движек (что крайне приятно). Интересными багами в eZPublish, надо
сказать, были уязвимости, связанные с поднятием привилегий (privilege
escalation). Таких оказалось аж целых две. Но, как это обычно бывает, в
бюллетенях безопасности сведения, раскрывающие их эксплуатацию, отсутствовали.
Блуждания по багтрекам также результатов не принесли.

Недолго думая, с офсайта была стянута уязвимая версия CMS, аналогичная той,
что использовалась на исследуемом ресурсе, с целью проведения тестирования
движки на уровне white-box. После загрузки комбо-инсталлятора «All-In-One» с
умным видом началась установка продукта, которая сводилась к многократному
прохождению диалогов аля «Next». Затем браузер отобразил диалог установки нового
сайта. Вскоре в моем распоряжении был полигон для тестирования.

 

Первый взгляд на пациента

После того, как приложение было развернуто в тестовой среде, браузер как-то
машинально оказался в панели администрирования сайтом. Покопавшись там немного,
я включил отладочный режим, который позволял видеть в браузере все запросы,
передаваемые к БД в процессе серфинга по сайту. Также это позволяло отслеживать
логику работы приложения.

Беглый осмотр админки показал, что могут возникнуть сложности на этапе
организации web-shell, так как CMS не позволяет работать непосредственно с
серверным кодом (читай – PHP). Приложение предусматривало работу с сайтом только
на уровне его контента. По большому счету это правильно, но для целей
проникновения, безусловно, не есть гуд.

Другое разочарование было связано с файлом «.htaccess» в корневой директории
web-сервера, который содержал следующие директивы:

...
<FilesMatch ".">
order allow,deny
deny from all
</FilesMatch>
<FilesMatch
"(index\.php|\.(gif|jpe?g|png|css|js|html)|var(.+)storage.pdf(.+)\.pdf)$">
order allow,deny
allow from all
</FilesMatch>
RewriteEngine On
RewriteRule !\.(gif|jpe?g|png|css|js|html)|var(.+)storage.pdf(.+)\.pdf$
index.php
...

Наличие подобной конфигурации свидетельствует о невозможности обращения к
каким-либо файлам в пространстве web-сервера в обход логики его работы. Отсюда
вытекает два неприятных момента для атакующего. Во-первых, невозможно
воспользоваться уязвимостями путем прямого обращения к серверным сценариям, в
которых не происходят соответствующие проверки. Во-вторых, возникают трудности
при заливке и использовании web-shell (обратиться к нему напрямую не получится).

Заоблачных перспектив по проведению успешной атаки не предвещал и
поверхностный взгляд на исходный код приложения. Разработчики этой CMS, видимо,
не понаслышке знакомы с темой безопасного web-программирования. Но что-то
подсказывало: свои косяки есть и тут, надо только лучше их разглядеть.

Вернувшись на офсайт eZPublish и перейдя на страницу с advisory, я стал
выбирать мишень для атаки. Из всего, что тут располагалось, меня привлекло
уведомление «Недостаточная обработка формы сделала возможным поднятие
привилегии». В бюллетене также говорилось, что уязвимость связана с регистрацией
нового пользователя. Ну что ж, посмотрим на этот процесс поближе.

Запустив OWASP WebScarab (кстати, рекомендую к использованию!) и настроев его
в качестве локального прокси, я обратился к странице регистрации нового
пользователя. Стоило мне вбить в форму регистрации произвольные данные, как
браузер редиректом перешел на страницу /user/success, где сообщалось, что
процесс завершился успешно и дальнейшие инструкции высланы на указанный мной при
регистрации e-mail. Здорово! Вот только SMTP-транспорт в моем случае настроен не
был, да и тестовый полигон находился в автономной сети. Казалось бы, сразу имеет
смысл по сорцам приложения подглядеть, каким образом происходит активация нового
пользователя, – если бы не одно «но».

Когда я просматривал процесс регистрации пользователя через WebScarab,
внимание мое привлекло использование нестандартных имен идентификаторов формы,
передаваемой серверу. Заключалась нестандартность в том, что на концах имен
параметров формы использовались цифровые значения, в которых явно прослеживалась
прямая последовательность. Кроме того, интересным моментом было то, что в форме
присутствовал скрытый параметр с именем UserId, который соответствовал
внутреннему идентификатору пользователя в таблице «ezuser» мускуля. Стоит
отметить, что идентификатор первого администратора является постоянным для всех
версий этой CMS. Это так, к слову.

После того, как процесс регистрации был повторен для другого пользователя, а
данные форм при регистрации первого и второго пользователей сравнены, догадка
подтвердилась: идентификаторы формы были последовательными.

Улавливаешь ход мысли, откуда ноги растут у адвизори? Именно! Обладая этой
информацией, несложно посчитать, какие данные должны быть указаны при
регистрации администратора с постоянным внутренним идентификатором. На скорую
руку я прикрутил SMTP-транспорт к CMS и отправил сырой POST-запрос на
регистрацию аккаунта с идентификатором дефолтового администратора с известным
мне адресом электронной почты и паролем. На мейл свалилось письмо, содержащее
ссылку для активации этого пользователя. Пользователь был успешно активирован, и
таким образом получен доступ к CMS с правами администратора в ней.

Однако радость длилась недолго. Хот я натравил сплоит на сайт, с которого все
началось, письмо, содержащее ссылку активации администратора с заданным мною
паролем, упорно не приходило. По всей видимости, это могло означать, что на
target-ресурсе почта во внешний мир не ходила (либо вообще не настроена). Вот
так вот, халява прошла стороной. И с этими мыслями я погрузился в сорцы CMS.

 

Так рождаются zero-day

В первую очередь я принялся изучать модули, связанные с процессами
аутентификации и авторизации. И в процессе этого творческого мероприятия
наткнулся на интересный участок кода:

...
if( $type == EZ_USER_PASSWORD_HASH_MD5_USER )
{
$str = md5( "$user\n$password" );
}
...

Это код создания хеша, по которому происходит процесс аутентификации. То, что
в качестве «соли» используется имя пользователя, – практика распространенная и
ей уже никого не удивишь. Фишка тут в следующем. В качестве разделителя
используется символ перевода строки, вследствие чего инструменты, которыми мы
привыкли пользоваться, откровенно лажаются (так как в них не предусмотрен
подобный фичесет). Так, например, InsidePro Password Pro идет лесом и при
встрече с подобными хешами приходится писать свой брутфорсер.

Добравшись до процесса активации нового пользователя и лицезрев код,
представленный ниже, я не смог сдержать ухмылки:

...
// Create enable account hash and send it to the newly registered user
$hash = md5( mktime( ) . $user->attribute( 'contentobject_id' )
...

В этих строках кода содержится уязвимость, которая связана с зависимостью
функции mktime( ) от времени, установленного на web-сервере. Значение
‘contentobject_id’ – это идентификатор пользователя в базе, который
последовательно меняется при регистрации новых пользователей. Таким образом,
зная время на удаленном сервере с eZPublish, можно достаточно тривиально
активировать учетную запись без получения активационной ссылки на мейл.
Установленное время на удаленном сервере передается каждый раз в заголовках
пакетов HTTP, возвращаемых сервером, поэтому проблем тут также не возникает.

На основе этих данных был написан сплоит, который меняет пароль
администратора CMS и активирует его учетную запись. В этот раз удача была на
моей стороне, и я легко получил доступ с правами администратора eZPublish на
сервере клиента.

 

Спускаемся на уровень оси

Помнишь, в самом начале говорилось, что eZPublish не позволяет редактировать
PHP? Вот об этом я и вспомнил, оказавшись внутри CMS под админом. Можно было бы
остановиться на достигнутом, но у меня появилось желание спуститься еще ниже: до
выполнения команд на сервере.

Вновь, но уже более пристально и внимательно, я пробежался по админке. Для
себя отметил, что может получиться реализовать идеи выполнения произвольного
PHP-кода путем изменения переменных окружения CMS. Но эту затею я решил оставить
на крайний случай. Наиболее простым решением получения шелла казалась установка
пакетов eZPublish, возможность чего присутствовала в панели администратора.

Обратившись уже в который раз к офсайту eZPublish, я проследовал к
репозитарию доступных пакетов для загрузки под исследуемую версию и слил к себе
на машину пару готовых примеров. Полученные файлы имели загадочное расширение
«ezpkg». Стоило изменить расширение на «zip», как файлы без проблем открылись –
в них содержалось еще по одному файлу с расширением «ezpkg». Проделав
аналогичную операцию с вложениями, я увидел обычный структурированный каталог,
содержащий различные файлы (в том числе, с расширениями PHP), в корне которого
находился файл «package.xml».

После установки пакета на тестовый сервер eZPublish, кроме появления нового
каталога в структуре web-сервера и надписи в разделе администрирования CMS о
том, что в системе установлен такой-то пакет, никаких изменений не произошло.
Немного осмотревшись, я просто добавил в разобранный пакет свой шелл и файл
«.htaccess», в котором переопределил FilesMatch и отключил RewriteEngine. Затем
залил этот заряженный пакет на многострадальный обследуемый сервер, но меня
ждало новое разочарование — в конфигурации apache присутствовала директива
«AllowOverride None» и переопределить директивы «FilesMatch» с использованием
файла «.htaccess» не представлялось возможным.

Еще немного времени было потрачено на анализ процесса заливки файла и разбор
файла «xml», содержащегося в пакете. Это позволило выявить уязвимость типа
«Обход каталога» (Path traversal), которая связана с обработкой файла
«package.xml». Предполагая, что некоторые файлы на web-сервере могут быть
перезаписаны, я подготовил новый пакет, который должен был при установке
перезаписать файл «ezinfo.php».

Стало возможным, не выходя за рамки логики работы приложения и используя
уязвимости на разных этапах его функционирования, получить доступ к командной
строке оси. Фактически это позволяет скомпрометировать весь web-сервер. В моем
случае были получены права apache, и хотя используемое ядро на исследуемом
ресурсе позволяло подняться до рута, делать я этого не стал, так как эти
действия уже выходили за рамки анализа защищенности web-приложения. Поэтому я
отписался о своих результатах коллеге по цеху и с чувством глубокого
удовлетворения потопал спать.

 

Занавес

Не одними SQL-инъекциями, File-инклудингом и прочими пряниками насыщен мир
web’а. Найдется место и более экзотическим багам, которые в совокупности порой
позволяют добиться высоких результатов при проникновении. Помни об этом. И удачи
тебе в исследованиях!

 

Danger

Внимание! Информация представлена исключительно с целью ознакомления! Ни
автор, ни редакция за твои действия при использовании описанных уязвимостей
ответственности не несут!

 

Info

При исследовании web-приложений методом white-box крайне полезно включение
различных отладочных режимов.

Функция mktime() возвращает метку времени Unix, соответствующую целому числу,
равному разнице в секундах между заданной датой/временем и началом Эпохи Unix
(The Unix Epoch, 1 января 1970 г).



Полную версию статьи
читай в мартовском номере
Хакера! На нашем диске ты найдешь poc-код для эксплуатации уязвимостей,
описанных в статье!

Оставить мнение

Check Also

Как работает Linux: от нажатия кнопки включения до рабочего стола

Лучший способ понять, как работает операционная система, — это проследить поэтапно ее загр…