«Занимательный XenAPI», или «Новые приключения Citrix XenServer»

«Занимательный XenAPI», или «Новые приключения Citrix XenServer»

Статья про сравнительное тестирование подсистемы безопасти RedHat Linux от Кирилла Ермакова, исследовательский центр Positive Research

«Занимательный XenAPI», или «Новые приключения Citrix XenServer» Статья про сравнительное тестирование подсистемы безопасти RedHat Linux от Кирилла Ермакова, исследовательский центр Positive Research Привет, коллеги!

Сегодня я хотел бы продолжить свое повествование о Citrix XenServer 5.6 и о разных аспектах работы с ним. В этот раз мне пришлось решать довольно простую (казалось бы!) проблему: исполнение команд в dom0 без применения SSH. Изучение возможностей для реализации привело к обнаружению некоторых забавных нюансов HTTP API данной ОС: способов получения /etc/passwd, удаленного выполнения rsync и набросков XenSource thin CLI protocol. Сейчас я расскажу вам, что называется, историю одного ресёрча…

Прежде всего, хотелось бы объяснить, как возникла подобная задача. В предыдущей серии я показывал публичную бета-версию секьюрити-гайда для XenServer, которую я «пилю» в надежде написать внятное руководство. Одна из рекомендаций (по аналогии с security hardening guide для VMWare ESXi) — отключение SSH-демона. Мотивация заключается в том, что в корпоративной версии Xen есть возможность использовать RBAC-систему с аутентификацией через Active Directory. Согласно рекомендациям вендора, этот путь с точки зрения безопасности является предпочтительным. После некоторой модификации сценариев запуска консоли на dom0, описанных в моем руководстве, попадание через нее в систему без пароля исключено. Соответственно, чтобы попасть непосредственно в консоль dom0 требуется знание не только пароля пользователя с правами pool-admin, но и данных учетной записи root.

ОК. Теперь перед нами встает задача удаленного аудита операционной системы при помощи автоматизированных средств. Все, что есть в нашем распоряжении, это XML-RPC, ведущая к XenAPI, документация на нее и исходники Xen-org на прекрасном языке OCaml. Нам же хочется выполнять команды в bash и получать их «выхлоп» для последующей обработки. Как это сделать?

Для начала нужно понять, почему нормальным путем (через консоль, предоставляемую в рамках API) это сделать не получится. Вспомним технологию вызова консоли со стороны клиента: вы подключаетесь к консоли (https:///console?ref=OpaqueRef:console_id), имея валидный session_id, и попадаете на RFB-терминал vncterm. Понятно, что данный протокол позволяет отправлять действия мышки и нажатия кнопок на удаленный сервер, а в ответ получать растровые изображения экрана. Дальнейшее очевидно: современные версии протокола RFB позволяют, кроме прочего, передавать файлы. Достаточно освоить еще и исполнение команд — и нет проблем. Однако это было бы слишком просто. В своих терминалах vncterm компания Citrix использует протокол RFB версии 003.003: в ней передача файлов еще не реализована.

С учетом этой печальной новости наша команда разработчиков принялась анализировать возможные методы реализации транспорта через RFB образца 1998 года. Идей появилось две. Первая — интеграция с ABBYY FineReader (с распознаванием текста на растровых изображениях, получаемых с dom0). Вторая — эмуляция движений мыши, которые позволяют выделить текст на экране и отправить его в буфер обмена, доступный в рамках протокола. Оба варианта при ближайшем рассмотрении напоминают бред сумасшедшего :)

Невеселые перспективы заставили меня вернуться к чтению документации для XenAPI. И я обратил внимание на то, с чем мне до этого не приходилось сталкиваться, — на плагинную архитектуру, а именно на возможность обращения к собственным исполняемым файлам через RPC-вызов call_plugin. Модули расположены в директории /etc/xapi.d/plugins/. Дальше все просто: созданный нами плагин вызывается

через XML-RPC и запускает соответствующий сценарий на Python, который реализует выполнение необходимых команд силами subprocess. Отлично! Методология выполнения команд на dom0 и получения от них ответа стала ясна.

Следующая проблема появилась сама собой: каким же образом наш плагин должен попасть на сервер? При решении этой проблемы, собственно, и обнаружились некоторые «подводные грабли» XenAPI.

Конечно же, меня заинтересовала функция, доступ к которой можно получить при помощи штатной утилиты xe.exe, — patch-upload. Она позволяет удаленно загружать файлы на XenServer и устанавливать их на весь пул серверов. Формат представления патча достаточно прост: это shar, упакованный в zip и подписанный (!) компанией Citrix. О том, как заглянуть в патч и установить его вручную, можно прочесть в заметке компании «Селектел». При загрузке патча его подпись сверяется с соответствующим набором открытых ключей в gpg keyring.

Таким образом, достаточно добавить собственную подпись в общую связку — и проблема разливки плагина отпадает. Собрать аналогичную конструкцию нетрудно, но чтобы залить свой ключ в связку необходимо иметь доступ к консоли. Получился замкнутый круг. Поэтому я начал искать способ залить свой плагин в обход стандартных методов.

Используя данный вызов, я отметил, что вызова https:///pool_patch_upload — нет в официальном описании API. Тому есть логичное объяснение: это действительно не часть API. Природное любопытство подсказывает вопрос: «А что же это тогда такое?». Способ найти ответ очень прост: Wireshark. Возможно, вы осудите меня за столь прямолинейный подход, но HTTP-интерфейс API операционной системы XenServer описан, к сожалению, чуть менее чем никак. А к моменту работы над этой проблемой я еще не понимал OCaml на таком уровне, чтобы анализировать исходный код достаточно эффективно.

Воспользовавшись замечательной возможностью Wireshark для расшифровки TLS и заботливо оставленным на виду сертификатом в /etc/xensource/, я получил дамп общения утилиты xe.exe (из состава XenCenter) с сервером. Я ожидал увидеть XML-RPC общение, описанное в официальной документации. Но не тут-то было!

Вместо этого в логе светился «POST /cli HTTP/1.0». Утилита забирала команду, ее атрибуты — и отправляла их на https:///cli. «Кажется, в супе чего-то не хватает». Из расшифровки протокола следовало, что есть некий XenSource thin CLI protocol который и использует утилита. Все пути вели на Github к исходникам XenAPI.

Проведя некоторое время за чтением исходных кодов этого прекрасного компонента гипервизора, я выяснил, что существует данное «XenSource thin CLI protocol» API версии 0.2, которое реализует выполнение команд хелпера xe.exe на удаленном хосте. Описано оно в файле xapi/cli_protocol.ml. Примечательно, что это «API будущего», призванное сделать из утилиты xe.exe всего лишь средство для пересылки команд, а обработчик встроить в XenAPI.

В целом обнаружение данного CLI API было судьбоносным: оно показало, что на порте 80\443 существует не только XML-RPC приемник и переключатель /console. Какие еще модули доступны через подобный вызов — случайно получилось найти в одном из файлов исходного кода (xen-api/ocaml/idl/constants.ml). Как легко можно догадаться, там обнаружилось множество вызовов, выдававших весьма интересную информацию. Меня покорил вызов https:///syns_config_files: при достаточных правах (pool-admin) вы получаете /etc/passwd (как я уже рассказывал в своих прошлых статьях, XenServer хранит хэш паролей именно там).

Еще один интересный вызов реализуется через “CONNECT /remotecmd?cmd=rsync&arg=some_nice_arg &pool_secret=your_pool_secret”. Он позволяет, зная значение /etc/xensource/ptoken, удаленно выполнять на сервере команду rsync с правами root. Это дает, в сущности, полный доступ к файловой системе. Но вы, наверное, спросите: «А как же добыть ptoken?».

Здесь все еще более тривиально. Разработчики Xensource создали возможность удаленно получать содержимое базы pool в виде XML-файла. Если выполнить на сервере запрос вида "GET /pool/xmldbdump?session_id=" то вы получите полный набор пар «ключ — значение», среди которых без труда можно найти нужный pool_token.

Ну и, собственно, сама удаленная загрузка патчей осуществляется через вызов "PUT /pool_patch_upload?session_id=". В ответ на него сервер напишет: «200, OK». И будет ждать, когда вы начнете заливать в сокет информацию. Как только вы загрузите файл, начнется проверка патча на валидность. Но есть одна особенность: пока вы держите коннект, API считает что вы все еще заливаете файл, и не трогает его (хотя файл уже создан в /var/patch). Проверки на длину файла я не обнаружил. Поскольку /var/patch находится в корневом разделе сервера, то DoS неизбежен в случае отправки туда /dev/urandom.

Конечно, это далеко не все. Приглядеться к вызовам и необходимым правам можно тут. Весь код отлично документирован, и мне кажется, что при наличии точно сформулированного вопроса найти в нем ответ не составит труда.

В целом же композиции описанных мною методов хватило для успешной заливки патча в систему без проверки подписи. Я не буду делать детальное описание методологии, ибо она граничит с понятием «эксплуатация уязвимости», но я думаю, что вы и сами все поняли :)

Спасибо за внимание!

Не ждите, пока хакеры вас взломают - подпишитесь на наш канал и станьте неприступной крепостью!

Подписаться