- Автор темы
- #1
Введение
Некоторое время назад у нас был случай судебной экспертизы, в котором сервер Linux был скомпрометирован, а модифицированный двоичный файл OpenSSH был загружен в память веб-сервера. Модифицированный бинарный файл OpenSSH использовался злоумышленниками в качестве бэкдора в систему. У клиента были файлы pcap и снимок гипервизора системы на момент взлома. Мы начали задаваться вопросом, можно ли расшифровать сеанс SSH и узнать о нем, восстановив ключевой материал из моментального снимка памяти. В этом блоге я расскажу о проведенных мною исследованиях OpenSSH и выпущу некоторые инструменты для выгрузки ключей сеанса OpenSSH из памяти, а также расшифровки и синтаксического анализа сеансов в сочетании с pcaps. Я также отправил свое исследование на конкурс плагинов Volatility 2020 .SSH протокол
Во-первых, я начал читать об OpenSSH и его работе. К счастью, OpenSSH имеет открытый исходный код, поэтому мы можем легко загрузить и прочитать детали реализации. RFC, хоть и были немного скучными для чтения, содержали в себе много информации. С первого взгляда протокол SSH выглядит следующим образом:1) Протокол SSH + обмен версией ПО
2) Согласование алгоритма (KEX INIT)
- Алгоритмы обмена ключами
- Алгоритмы шифрования
- Алгоритмы MAC
- Алгоритмы сжатия
4) Аутентификация пользователя
5) Клиент запрашивает канал типа «session»
6) Клиент запрашивает псевдотерминал
7) Клиент взаимодействует с сеансом
Начиная с начала, клиент подключается к серверу и посылает версию протокола и версию программного обеспечения:SSH-2.0-OpenSSH_8.3. Сервер отвечает своим протоколом и версией программного обеспечения. После этого первоначального обмена протоколом и версией программного обеспечения весь трафик упаковывается в кадры SSH. Кадры SSH существуют в основном из длины, длины заполнения, данных полезной нагрузки, содержимого заполнения и MAC. Пример фрейма SSH:
Затем клиент отправит на сервер сообщение KEX_INIT, чтобы начать согласование параметров сеанса, таких как обмен ключами и алгоритм шифрования. В зависимости от порядка этих алгоритмов клиент и сервер выберут первый предпочтительный алгоритм, который поддерживается обеими сторонами. После сообщения KEX_INIT происходит обмен несколькими сообщениями, связанными с обменом ключами, после чего сообщения NEWKEYS отправляются с обеих сторон. Это сообщение говорит другой стороне, что все настроено для начала шифрования сеанса, и следующий кадр в потоке будет зашифрован. После того, как обе стороны примут новые ключи шифрования в действие, клиент запросит аутентификацию пользователя и в зависимости от настроенных механизмов аутентификации на сервере выполнит аутентификацию на основе пароля/ключа/ и т. д. После аутентификации сеанса клиент откроет канал,
Восстановление ключей сеанса
Первым шагом в восстановлении ключей сеанса был анализ исходного кода OpenSSH и отладка существующих двоичных файлов OpenSSH. Я попробовал сам скомпилировать OpenSSH, записав где-нибудь сгенерированные ключи сеанса, подключив отладчик и выполнив поиск ключей в памяти программы. Успех! Ключи сеанса хранились в памяти в куче. Еще немного покопавшись в исходном коде, я обратил внимание на функции, отвечающие за отправку и получение кадра NEWKEYS. Я обнаружил, что существует структура «ssh», в которой хранится структура «session_state». Эта структура, в свою очередь, содержит все виды информации, относящиеся к текущему сеансу SSH, включая структуру newkeys, содержащую информацию, касающуюся шифрования, MAC и алгоритма сжатия. На один уровень ниже мы, наконец, находим структуру sshenc, содержащую имя шифра, ключ, IV и длину блока. Все, что нам нужно! Хороший обзор структуры OpenSSH показан ниже:
- name, cipher, key и iv являются действительными указателями
- name указывает на допустимое имя шифра, которое равно cipher->name
- key_len находится в допустимом диапазоне
- iv_len находится в допустимом диапазоне
- block_size находится в допустимом диапазоне
Расшифровка и разбор трафика
Восстановление ключей сеанса, которые используются для шифрования и дешифрования трафика, было успешным. Следующее - расшифровка трафика! Я начал разбирать некоторые pcap-файлы с помощью pynids, библиотеки синтаксического анализа и повторной сборки TCP. Я использовал нашу собственную библиотеку dissect.cstruct для анализа структур данных и разработала структуру синтаксического анализатора, для анализа протоколов, таких как ssh. Фреймворк синтаксического анализа в основном подает пакеты синтаксическому анализатору протокола в правильном порядке, поэтому, если клиент отправляет 2 пакета, а сервер отвечает 3 пакетами, пакеты также будут доставлены синтаксическому анализатору в том же порядке. Это важно для сохранения общего состояния протокола. Анализатор в основном использует кадры SSH до тех пор, пока не встретится кадр NEWKEYS, указывающий, что следующий кадр зашифрован. Теперь парсер просматривает следующий кадр в потоке из этого источника и перебирает предоставленные ключи сеанса, пытаясь расшифровать кадр. В случае успеха парсер устанавливает сеансовый ключ в состоянии для расшифровки оставшихся в сеансе кадров. Парсер может обрабатывать практически все алгоритмы шифрования, поддерживаемые OpenSSH.
Вывод
Подводя итог, я исследовал протокол SSH, узнал как ключи сеанса хранятся в памяти для OpenSSH, нашел способ очистить их из памяти и использовать их в сетевом парсере для расшифровки и синтаксического анализа сеансов SSH с получением удобочитаемого вывода. Скрипты, использованные в этом исследовании, можно найти здесь:- Автономный Python POC для сброса ключей сеанса SSH
- Плагин Volatility 2
- Плагин Volatility 3
- Парсер протокола SSH
Последние мысли
Как ни странно, во время своего исследования я также наткнулся на эти прокомментированные строки в функции ssh_set_newkeys в исходном коде OpenSSH. Какая ирония! Если бы эти строки были раскомментированы и скомпилированы в двоичных файлах OpenSSH, это исследование было бы намного сложнее...
- Telegram
