В этой статье я покажу, как работа­ет опас­ная уяз­вимость в механиз­ме десери­али­зации Jenkins, которая ведет к ком­про­мета­ции дан­ных, а иног­да и к пол­ному зах­вату сер­вера. Пос­мотрим, как взла­мыва­ют сер­веры CI/CD и что про­исхо­дит в коде во вре­мя ата­ки.

Jenkins — популяр­ная бес­плат­ная плат­форма CI/CD, инс­тру­мент неп­рерыв­ной интегра­ции и раз­верты­вания. Коман­ды раз­работ­чиков исполь­зуют ее для выкаты­вания новых вер­сий про­дук­тов в про­дак­шен. DevOps-инже­нер выс­тра­ивает пай­плайн, вклю­чающий юнит‑тес­ты и допол­нитель­ные эта­пы, которые дол­жны выпол­нять­ся при каж­дой пуб­ликации. Сис­тема авто­мати­чес­ки про­гоня­ет новый код по этой цепоч­ке.

Jenkins стал отрасле­вым стан­дартом, его исполь­зуют тысячи ком­паний и неболь­ших команд раз­работ­чиков. Его раз­ворачи­вают на собс­твен­ных сер­верах, поэто­му уяз­вимость CVE-2026-53435 край­не опас­на: фак­тичес­ки она может стать откры­тыми ворота­ми в кор­поратив­ную сеть.

CVE-2026-53435 — это уяз­вимость десери­али­зации дан­ных с оцен­кой опас­ности 8,8 по CVSS v3.1. Более высокую оцен­ку она не получи­ла, пос­коль­ку для экс­плу­ата­ции нуж­на минималь­ная авто­риза­ция. Поль­зователь с низ­кими пра­вами может отпра­вить спе­циаль­но сфор­мирован­ный файл config.xml. Это не гло­баль­ный кон­фиг: ата­ка про­водит­ся на уров­не дос­тупных поль­зовате­лю объ­ектов, таких как View или Job.

Из‑за недос­таточ­ной филь­тра­ции Jenkins про­пус­тит про­изволь­ные клас­сы Java. За сери­али­зацию и десери­али­зацию отве­чает XStream, в котором есть класс для чте­ния свой­ств DescribableList — спе­циаль­ный объ­ект для вза­имо­дей­ствия с пла­гина­ми. В DescribableList нет филь­тра­ции: все свой­ства авто­мати­чес­ки счи­тают­ся безопас­ными и обра­баты­вают­ся как ViewProperty.

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

warning

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

 

Тестовый стенд

Для прак­тики под­нимем кон­тей­нер Docker. Соз­дадим файл docker-compose.yml:

version: "3.8"
services:
jenkins:
build: .
container_name: jenkins-vuln-lab
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
environment:
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
networks:
default:
name: jenkins-lab-net
volumes:
jenkins_home:

Прос­то запус­тить Jenkins недос­таточ­но — нуж­на минималь­ная нас­трой­ка. В той же пап­ке соз­даем Dockerfile:

FROM jenkins/jenkins:2.567-jdk21
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN jenkins-plugin-cli -f /usr/share/jenkins/ref/plugins.txt
COPY init.groovy.d/ /usr/share/jenkins/ref/init.groovy.d/

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии