Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов

Введение

Jenkins — это широко используемый инструмент для автоматизации задач, таких как сборка, тестирование и развёртывание программного обеспечения. Он является важной частью процесса разработки во многих организациях. Если злоумышленник получает доступ к серверу Jenkins, это может привести к серьёзным последствиям, таким как кража учетных данных, манипуляции с кодом или даже срыв процессов развёртывания. Доступ к Jenkins предоставляет злоумышленнику возможность вмешаться в программный конвейер, что может привести к хаосу в процессе разработки и компрометации конфиденциальных данных.

В этой статье мы рассмотрим консультативное заключение по уязвимости CVE-2024-43044, которая представляет собой уязвимость, связанную с произвольным чтением файлов в Jenkins. Мы покажем, как можно использовать эту уязвимость для эскалации привилегий с целью достижения удалённого выполнения кода (RCE) на контроллере Jenkins при захвате агента Jenkins.

Обзор архитектуры Jenkins

Архитектура Jenkins основана на модели "контроллер-агенты", где контроллер Jenkins является основным узлом в установке Jenkins. Контроллер управляет агентами Jenkins и координирует их работу, включая планирование задач на агентах и мониторинг их состояния [3]. Взаимодействие между контроллером и агентами может происходить через Inbound-соединение (ранее известное как "JNLP") или SSH.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #1

Реализация коммуникационного слоя, который обеспечивает межпроцессное взаимодействие, выполняется в библиотеке Remoting/Hudson [4]. В репозитории [5] также содержится полезная документация о том, как работает библиотека Remoting/Hudson. На изображении ниже показаны некоторые важные компоненты этой архитектуры.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #2

Анализ уязвимости

Команда Jenkins выпустила консультативное заключение (SECURITY-3430 / CVE-2024-43044) [1], касающееся уязвимости, связанной с произвольным чтением файлов, которая позволяет агенту читать файлы с контроллера. Это происходит из-за функции, позволяющей контроллеру передавать JAR-файлы агентам. Согласно заключению, проблема заключается в том, что "реализация метода ClassLoaderProxy#fetchJar, вызываемого на контроллере, не ограничивает пути, по которым агенты могут запрашивать файлы из файловой системы контроллера".

Среди коммитов, связанных с уязвимостью, имеется тест [7], содержащий код для эксплуатации этой уязвимости.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #3

Этот код в первую очередь получает доступ к классу hudson.remoting.RemoteClassLoader, который отвечает за загрузку файлов классов с удаленного узла через канал. Конкретно он обращается к объекту Proxy, находящемуся в поле proxy класса RemoteClassLoader. Обработчик для этого Proxy является экземпляром класса hudson.remoting.RemoteInvocationHandler.

Затем код использует этот обработчик для вызова метода fetchJar, что приводит к выполнению метода hudson.remoting.RemoteInvocationHandler.invoke. Этот процесс, в свою очередь, подготавливает удалённый вызов процедуры (RPC) к контроллеру. На стороне контроллера вызов достигает метода hudson.remoting.RemoteClassLoader$ClassLoaderProxy.fetchJar. Как показано ниже, метод fetchJar на контроллере не проверяет URL (который контролируется пользователем) и загружает ресурс без валидации.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #4

Ниже представлено изображение, которое помогает визуализировать этот процесс.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #5

Эта уязвимость позволяет обойти систему контроля доступа "Agent -> Controller" [13], которая включена по умолчанию с версии Jenkins 2.326 для управления доступом агентов к контроллеру и предотвращения захвата контроля над ним.

Патч

Патч вводит валидатор и некоторые системные свойства Java для контроля функциональности fetchJar.

Системные свойства Java включают:

  • jenkins.security.s2m.JarURLValidatorImpl.REJECT_ALL — Отклоняет любую попытку получения JAR-файла.
  • hudson.remoting.Channel.DISABLE_JAR_URL_VALIDATOR — Отключает проверку валидности URL.

Валидатор проверяет, указывает ли запрашиваемый URL на допустимый JAR-файл (JAR-файл из плагинов или ядра), как видно из приведённых ниже фрагментов кода:

jenkinsci/remoting/src/main/java/hudson/remoting/RemoteClassLoader.java

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #6

jenkinsci/jenkins/core/src/main/java/jenkins/security/s2m/JarURLValidatorImpl.java

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #7

Обратитесь к рекомендациям по устранению уязвимостей для получения дополнительной информации и методов обхода.

Получение удалённого выполнения кода (RCE).

Предварительные условия

Согласно рекомендациям, атака может быть инициирована «процессами агентов, кодом, работающим на агентах, или злоумышленниками, обладающими разрешением Agent/Connect» [1]. Мы реализовали наш эксплойт с учётом гибкости, поддерживая как агентов с обратной связью [15], так и SSH-подключения.

Использование секрета для агента с обратной связью

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

  • URL целевого сервера Jenkins;
  • Имя агента;
  • Секрет агента.

Один из способов получения этой информации — после получения доступа к узлу агента просмотреть все запущенные процессы. Вероятнее всего, вы обнаружите процесс Java, в котором эти данные указаны в командной строке, так как это является стандартным способом подключения агентов с обратной связью, предложенным Jenkins после их настройки.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #8

Другой способ получения информации — утечка учетных данных. Следует отметить, что перед запуском нашего агента необходимо завершить работу уже запущенного агента или дождаться его отключения, так как один и тот же агент не может подключаться к серверу Jenkins более одного раза одновременно.

Пример запуска эксплойта этим способом:

java -jar exploit.jar mode_secret http://localhost:8080/ test b55d9b7fede47864572f4d0830a564a83ae78a4f297c1178b7f55601784f645c

Подключение к уже запущенному процессу Remoting

В этом режиме мы подключаемся к уже запущенному процессу Remoting с помощью API инструментария Java [16]. Мы подключаем Java-агент, который выполнит эксплуатацию уязвимости.

Это особенно полезно, когда подключение агент/контроллер происходит через SSH, так как в этом режиме не используется секрет агента. SSHLauncher, запущенный на контроллере, выполняет команду:

java -jar remoting.jar -workDir WORKDIR -jar-cache WORKDIR/remoting/jarCache

через сессию SSH и перенаправляет ввод и вывод для создания канала связи с агентом.

Например, при атаке с использованием вредоносного скрипта сборки, загруженного в кодовый репозиторий, управление сборкой которого осуществляется через Jenkins (запущенный на агенте), злоумышленник не сможет получить имя агента или его секрет, поскольку они не существуют в этом сценарии. В таком случае будет запущен процесс Remoting, подключенный к контроллеру через каналы SSH. Наш эксплойт найдет PID этого процесса и внедрит в него Java-код для выполнения следующих шагов.

Чтобы использовать этот режим, вам потребуется предоставить следующую информацию:

  • URL целевого сервера Jenkins (опционально — эксплойт использует IP-адрес контроллера, подключенного через SSH, и создаёт URL Jenkins как http://IP:8080/. В этом случае на машине должны быть установлены утилиты pgrep, ps и netstat);
  • Команда, которая будет выполнена.

Изображение ниже демонстрирует пример атаки, в которой pipeline выполняет команду mvn package внутри ненадёжного клонированного репозитория. Предположим, Jenkins настроен так, чтобы не выполнять сборки локально на контроллере через встроенный узел. Этого достаточно, чтобы скомпрометировать контроллер Jenkins:

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #9

Вредоносному репозиторию в этой настройке нужны только два файла:

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #10

Чтение произвольных файлов

Когда предоставляется секрет/имя агента, эксплойт использует его для установления соединения с сервером Jenkins, используя библиотеку Remoting. Мы используем класс Engine и ожидаем, пока соединение не будет установлено. Однако при подключении к уже существующему подключенному агенту эти шаги пропускаются.

Затем мы получаем экземпляр hudson.remoting.RemoteClassLoader из одного из запущенных потоков.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #11

Мы используем его для создания объекта reader, который обрабатывает вызов метода fetchJar().

if (this.ccl == null) this.ccl = this.getRemoteClassLoader();
 
this.reader = new RemoteFileReader(this.ccl);

С помощью этого объекта мы можем использовать его для загрузки файлов с сервера. Не требуется обхода пути, вы можете запросить файлы, указав их полный путь, например:

this.reader.readAsString("file:///etc/passwd");

Подделка действительных файлов cookie пользователя

В рекомендации [1] подтверждается, что RCE возможен с этой уязвимостью, и указывается на вторую рекомендацию [2] по другой уязвимости для чтения файлов, выпущенной в январе 2024 года, в которой перечислены некоторые способы получения RCE с такого рода недостатками в Jenkins.

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #12

Один из подходов привлек наше внимание, так как он не требует изменения конфигурации, то есть работает против стандартной установки. Техника удаленного выполнения кода через куки-файл «Remember me» (Запомнить меня) заключается в подделке куки для учетной записи администратора, что позволяет злоумышленнику войти в приложение и получить доступ к консоли сценариев для выполнения команд.

Требования для применения этой техники:

  • Включена функция «Remember me» (по умолчанию).
  • Злоумышленники могут получить бинарные секреты.
  • Злоумышленники имеют разрешение Overall/Read, чтобы иметь возможность читать содержимое файлов, превышающее несколько первых строк.

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

Для создания действительного куки требуется определённые данные. В нашей реализации мы использовали следующий подход:

  1. Чтение файла $JENKINS_HOME/users/users.xml для получения списка пользователей, имеющих учетные записи на сервере Jenkins;
  2. Чтение каждого файла $JENKINS_HOME/users/*.xml, чтобы извлечь информацию о пользователях, такую как: имя пользователя, user seed, временная метка и хэш пароля;
  3. Чтение необходимых файлов для подписи куки: Имея эти данные, мы воспроизводим алгоритм подписания куки в Jenkins [8], который можно описать следующим псевдокодом [6]:
    1. $JENKINS_HOME/secret.key
    2. $JENKINS_HOME/secrets/master.key
    3. $JENKINS_HOME/secrets/org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac

Имея эти данные, мы воспроизводим алгоритм подписания куки в Jenkins [8], который можно описать следующим псевдокодом [6]:

Анализ CVE-2024-43044 — от чтения файлов до удаленного выполнения кода в Jenkins через агентов, image #13

Этот куки-файл может быть отправлен как “Cookie: remember-me=VALUE” в запросах к веб-приложению Jenkins.

Выполнение кода

После того как мы получили куки-файл "remember-me", мы можем запросить CSRF-токен (называемый Jenkins-Crumb) по адресу /crumbIssuer/api/json. Также стоит захватить куки-файл JSESSIONID, полученный в ответе, так как эти два файла связаны.

Затем мы отправляем POST-запрос на /scriptText, передавая значение Jenkins-Crumb в заголовке и значение JSESSIONID в куки, наряду с куки "remember-me". Код Groovy, который должен быть выполнен, передается через параметр POST с именем "script".

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

curl -X POST "$JENKINS_URL/scriptText" --cookie "remember-me=$REMEMBER_ME_COOKIE; JSESSIONID...=$JSESSIONID" --header "Jenkins-Crumb: $CRUMB" --header "Content-Type: application/x-www-form-urlencoded" --data-urlencode "script=$SCRIPT"

Выполнение команды с помощью Groovy так же просто, как выполнение:

println "uname -a".execute().text

Итоги эксплойта

Это краткий обзор шагов, присутствующих в нашем эксплойте:

  1. Получить ссылку на hudson.remoting.RemoteClassLoader;
  2. Создать читатель файлов с его помощью;
  3. Прочитать необходимые файлы (всего 3) для подделки куки-файла для данного пользователя;
  4. Прочитать список пользователей Jenkins;
  5. Получить информацию (id, временная метка, seed и хэш) о каждом отдельном пользователе;
  6. Подделать куки-файл "remember-me" для пользователей до получения доступа к Сценарному движку Jenkins;
  7. Использовать Сценарный движок Jenkins для выполнения системных команд;
  8. Получить имена пользователей и хэши в формате, готовом для взлома с помощью John the Ripper [14].

Стоит отметить, что мы тестировали наш эксплойт только на Jenkins Docker, но считаем, что он должен работать и на других установках с небольшими или без изменений.

Код эксплойта можно найти по адресу: https://github.com/convisolabs/CVE-2024-43044-jenkins

Заключение

В этом посте мы описали наш подход к эксплуатации уязвимости, связанной с CVE-2024-43044, для достижения удаленного выполнения кода (RCE) на уязвимом сервере Jenkins. Хотя существует множество различных окружений, использующих Jenkins, которые не охвачены в данном анализе, мы разработали эксплойт так, чтобы его было легко адаптировать под нужды других исследователей. Мы также считаем, что некоторые части могут быть повторно использованы в других эксплойтах для уязвимостей чтения файлов в Jenkins.

Ссылки

  1. https://www.jenkins.io/security/advisory/2024-08-07/#SECURITY-3430
  2. https://www.jenkins.io/security/advisory/2024-01-24/#SECURITY-3314
  3. https://www.jenkins.io/doc/book/using/using-agents/
  4. https://www.jenkins.io/projects/remoting/
  5. https://github.com/hudson/www/
  6. https://gist.github.com/mtiennnnn/551b7320c064db02aad815c6bdb91d9
  7. https://github.com/jenkinsci/jenkins/blob/203b6a6c851697e83aefc37d1812bfde06390bfe/test/src/test/java/jenkins/security/Security3430Test.java#L244
  8. https://github.com/jenkinsci/jenkins/blob/jenkins-2.470/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java#L174
  9. https://hub.docker.com/r/jenkins/jenkins
  10. https://www.jenkins.io/doc/book/managing/system-properties/
  11. https://naiwaen.debuggingsoft.com/blog/wp-content/uploads/2022/06/2022-05-28_201016.jpg
  12. https://github.com/advisories/GHSA-h856-ffvv-xvr4
  13. https://www.jenkins.io/doc/book/security/controller-isolation/#agent-controller-access-control
  14. https://www.openwall.com/john/
  15. https://github.com/jenkinsci/remoting/blob/master/docs/inbound-agent.md
  16. https://www.baeldung.com/java-instrumentation

LHMedia в телеграме:

#cve #rce #jenkins #уязвимость

1405 views·6 shares