Concourse Enumeration & Attacks
Перелік та Атаки Concourse
Ролі та Дозволи Користувачів
Concourse має п'ять ролей:
Concourse Адміністратор: Ця роль надається тільки власникам головної команди (типова початкова команда Concourse). Адміністратори можуть налаштовувати інші команди (наприклад:
fly set-team
,fly destroy-team
...). Дозволи цієї ролі не можуть бути змінені за допомогою RBAC.власник: Власники команд можуть змінювати все в межах команди.
учасник: Учасники команд можуть читати та записувати в активи команди, але не можуть змінювати налаштування команди.
оператор конвеєра: Оператори конвеєра можуть виконувати операції конвеєра, такі як запуск будівель та закріплення ресурсів, проте вони не можуть оновлювати конфігурації конвеєра.
спостерігач: Учасники команд мають "тільки для читання" доступ до команди та її конвеєрів.
Крім того, дозволи ролей власника, учасника, оператора конвеєра та спостерігача можуть бути змінені шляхом налаштування RBAC (більш конкретно налаштовуючи його дії). Докладніше про це читайте за посиланням: https://concourse-ci.org/user-roles.html
Зверніть увагу, що Concourse групує конвеєри в межах Команд. Тому користувачі, які належать до Команди, зможуть керувати цими конвеєрами та можуть існувати кілька Команд. Користувач може належати до кількох Команд та мати різні дозволи в кожній з них.
Змінні та Менеджер Облікових Даних
У конфігураціях YAML ви можете налаштовувати значення за допомогою синтаксису ((_source-name_:_secret-path_._secret-field_))
.
З документації: source-name є необов'язковим, і якщо його пропущено, буде використовуватися кластерний менеджер облікових даних, або значення може бути надано статично.
Необов'язкове _secret-field_ вказує поле в отриманому секреті для читання. Якщо його пропущено, менеджер облікових даних може вибрати читати 'типове поле' з отриманого облікового запису, якщо поле існує.
Крім того, secret-path та secret-field можуть бути оточені подвійними лапками "..."
, якщо вони містять спеціальні символи як, наприклад, .
та :
. Наприклад, ((source:"my.secret"."field:1"))
встановить secret-path на my.secret
та secret-field на field:1
.
Статичні Змінні
Статичні змінні можна вказати в кроках завдань:
Або використовуючи наступні fly
аргументи:
-v
або--var
NAME=VALUE
встановлює рядокVALUE
як значення для змінноїNAME
.-y
або--yaml-var
NAME=VALUE
розбираєVALUE
як YAML та встановлює його як значення для змінноїNAME
.-i
або--instance-var
NAME=VALUE
розбираєVALUE
як YAML та встановлює його як значення для змінної екземпляраNAME
. Див. Групування конвеєрів, щоб дізнатися більше про змінні екземпляра.-l
або--load-vars-from
FILE
завантажуєFILE
, YAML-документ, що містить відображення назв змінних на значення, та встановлює їх всі.
Управління обліковими даними
Існують різні способи вказання Менеджера облікових даних в конвеєрі, дивіться як у https://concourse-ci.org/creds.html. Крім того, Concourse підтримує різні менеджери облікових даних:
Зверніть увагу, що якщо у вас є якийсь вид доступу на запис до Concourse, ви можете створити завдання для ексфільтрації цих секретів, оскільки Concourse повинен мати до них доступ.
Перелік Concourse
Для переліку середовища Concourse спочатку потрібно зібрати дійсні облікові дані або знайти аутентифікований токен, ймовірно, у файлі конфігурації .flyrc
.
Вхід та перелік поточного користувача
Для входу вам потрібно знати кінцеву точку, назву команди (за замовчуванням
main
) та команду, до якої належить користувач:fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
Отримати налаштовані цілі:
fly targets
Перевірити, чи підключення до налаштованої цілі є дійсним:
fly -t <ціль> status
Отримати роль користувача щодо вказаної цілі:
fly -t <ціль> userinfo
Зверніть увагу, що токен API за замовчуванням зберігається в $HOME/.flyrc
, якщо ви здійснюєте обшук машин, ви можете знайти там облікові дані.
Команди та користувачі
Отримати список команд
fly -t <ціль> teams
Отримати ролі всередині команди
fly -t <ціль> get-team -n <назва-команди>
Отримати список користувачів
fly -t <ціль> active-users
Конвеєри
Перелік конвеєрів:
fly -t <ціль> pipelines -a
Отримати yaml конвеєра (чутлива інформація може бути знайдена в означенні):
fly -t <ціль> get-pipeline -p <назва-конвеєра>
Отримати всі оголошені змінні конвеєра
for pipename in $(fly -t <ціль> pipelines | grep -Ev "^id" | awk '{print $2}'); do echo $pipename; fly -t <ціль> get-pipeline -p $pipename -j | grep -Eo '"vars":[^}]+'; done
Отримати всі назви секретів конвеєра, які використовуються (якщо ви можете створити/змінити завдання або захопити контейнер, ви можете їх ексфільтрувати):
Контейнери та Робочі
Список робочих:
fly -t <ціль> workers
Список контейнерів:
fly -t <ціль> containers
Список збірок (щоб побачити, що запущено):
fly -t <ціль> builds
Атаки на Concourse
Брутфорс Креденціалів
admin:admin
test:test
Перелік секретів та параметрів
У попередньому розділі ми побачили, як ви можете отримати всі назви секретів та змінних, які використовуються в конвеєрі. Змінні можуть містити чутливу інформацію, а назва секретів буде корисною пізніше для спроби їх вкрасти.
Сесія всередині запущеного або недавно запущеного контейнера
Якщо у вас достатньо привілеїв (роль учасника або вище), ви зможете перелічити конвеєри та ролі та просто отримати сесію всередині контейнера <конвеєр>/<завдання>
використовуючи:
З цими дозволами ви можете:
Вкрасти секрети всередині контейнера
Спробувати вибратися на вузол
Перелічити/зловживати кінцеву точку метаданих хмари (з контейнера та з вузла, якщо це можливо)
Створення/зміна конвеєра
Якщо у вас достатньо привілеїв (роль учасника або вище), ви зможете створювати/змінювати нові конвеєри. Перевірте цей приклад:
Після модифікації/створення нового конвеєра ви зможете:
Вкрасти секрети (через їх виведення або отримання всередині контейнера та запуску
env
)Вийти на вузол (надавши достатньо привілеїв -
privileged: true
)Перелічити/зловживати кінцеву точку метаданих хмари (з підпростору та з вузла)
Видалити створений конвеєр
Виконання власного завдання
Це схоже на попередній метод, але замість модифікації/створення цілком нового конвеєра ви можете просто виконати власне завдання (що, ймовірно, буде набагато прихованіше):
Втеча на вузол з привілейованого завдання
У попередніх розділах ми бачили, як виконати привілейоване завдання з Concourse. Це не надасть контейнеру точно такий самий доступ, як прапорець привілеїв в контейнері Docker. Наприклад, ви не побачите пристрій файлової системи вузла в /dev, тому втеча може бути більш "складною".
У наступному PoC ми збираємося використати release_agent для втечі з деякими невеликими модифікаціями:
Як ви могли помітити, це просто звичайний втеча агента випуску, просто змінюючи шлях cmd вузла
Втеча на вузол з контейнера робочого процесу
Для цього достатньо звичайної втечі агента випуску з незначними змінами:
Втеча на вузол з контейнера веб-сервера
Навіть якщо контейнер веб-сервера має вимкнені деякі захисти, він не працює як звичайний привілейований контейнер (наприклад, ви не можете монтувати і можливості дуже обмежені, тому всі прості способи втечі з контейнера є некорисними).
Проте, він зберігає локальні облікові дані у відкритому вигляді:
Ви можете використати ці дані для входу на веб-сервер та створення привілейованого контейнера та виходу на вузол.
У середовищі ви також можете знайти інформацію для доступу до інстанції postgresql, яку використовує concourse (адреса, ім'я користувача, пароль та база даних серед іншої інформації):
Зловживання Garden Service - Не справжня атака
Це лише цікаві примітки про сервіс, але через те, що він прослуховує лише локальний хост, ці примітки не матимуть жодного впливу, який ми вже не використовували раніше.
За замовчуванням кожний робочий процес Concourse буде запускати службу Garden на порту 7777. Ця служба використовується веб-мастером для вказівки робочому процесу що потрібно виконати (завантажити зображення та виконати кожне завдання). Це звучить досить добре для атакування, але є деякі хороші захисти:
Він просто відкритий локально (127..0.0.1) і я думаю, що коли робочий процес аутентифікується знову у веб-сервері з допомогою спеціальної служби SSH, створюється тунель, щоб веб-сервер міг спілкуватися з кожною службою Garden всередині кожного робочого процесу.
Веб-сервер моніторить робочі контейнери кожні кілька секунд, і несподівані контейнери видаляються. Тому, якщо ви хочете запустити власний контейнер, вам потрібно втручатися у комунікацію між веб-сервером та службою Garden.
Робочі процеси Concourse працюють з високими привілеями контейнера:
Проте, техніки, такі як монтування пристрою /dev вузла або release_agent не працюватимуть (оскільки реальний пристрій з файловою системою вузла недоступний, лише віртуальний). Ми не можемо отримати доступ до процесів вузла, тому вибратися з вузла без використання вразливостей ядра стає складним.
У попередньому розділі ми побачили, як вибратися з привілейованого контейнера, тому якщо ми можемо виконати команди в привілейованому контейнері, створеному поточним робітником, ми можемо вибратися на вузол.
Зверніть увагу, що під час експериментів з Concourse я помітив, що коли створюється новий контейнер для виконання чогось, процеси контейнера доступні з контейнера робітника, тому це схоже на те, що контейнер створює новий контейнер всередині себе.
Вхід в робочий привілейований контейнер
Створення нового привілейованого контейнера
Ви можете дуже легко створити новий контейнер (просто запустіть випадковий UID) та виконати щось на ньому:
Проте веб-сервер перевіряє кожні кілька секунд контейнери, які працюють, і якщо виявиться неочікуваний, він буде видалений. Оскільки спілкування відбувається через HTTP, ви можете втрутитися у комунікацію, щоб уникнути видалення неочікуваних контейнерів:
Посилання
https://concourse-ci.org/vars.html
Last updated