Компания Qualys выявила удалённо эксплуатируемую уязвимость (CVE-2023-38408) в реализации ssh-agent из состава OpenSSH, позволяющую выполнить код в системе, предоставившей доступ к ssh-agent для хоста на другом конце ssh-соединения. Совершение атаки возможно только если пользователь подключился по ssh к системе, контролируемой злоумышленником, включив проброс сокета к ssh-agent по ssh при помощи опции “-A” или настройки ForwardAgent в файле конфигурации. Кроме того, для успешной атаки в системе жертвы должны присутствовать определённые библиотеки. Исследователями подготовлены прототипы эксплоитов, работа которых продемонстрирована в Ubuntu 22.04 и 21.10.
Процесс ssh-agent, применяемый для кэширования закрытых ключей при аутентификации по открытым ключам, поддерживает опциональный режим проброса, позволяющий удалённой стороне ssh-соединения обращаться к ssh-agent на
локальной системе для того чтобы не хранить данные аутентификации на других хостах.
Уязвимость связана с наличием в ssh-agent поддержки загрузки модулей PKCS#11, которая может быть инициирована в том числе через проброшенный на другую систему unix-сокет к ssh-agent. Данная возможность позволяет атакующему, контролирующему хост, к которому произведено подключение, загружать и сразу выгружать в отдельном процессе ssh-pkcs11-helper любые разделяемые библиотеки из каталогов /usr/lib* на локальной системе жертвы. Данная особенность проявляется в ssh-agent, собранном с параметром ENABLE_PKCS11, который включён по умолчанию.
Изначально возможность загрузки разделяемых библиотек не рассматривалась как угроза безопасности, так как загрузка возможна только из системных каталогов /usr/lib*, в которых находятся официально поставляемые дистрибутивом библиотеки, а операции с данными библиотеками ограничены вызовом функций dlopen() и dlclose(), без обращения к функциям библиотек. Тем не менее, было упущено из виду, что некоторые библиотеки имеют функции-конструкторы и деструкторы, автоматически вызываемые при выполнении операций dlopen() и dlclose(). Этого может быть достаточно, чтобы подобрать нужные библиотеки и организовать удалённое выполнение кода.
Всего в поставке Ubuntu выявлено 58 библиотек, делающих стек исполняемым при вызове dlopen() и оставляющих его в таком состоянии после вызова dlclose(); 16577 библиотек изменяют раскладку mmap после вызова dlopen(); 9 библиотек регистрируют обработчик SIGSEGV при вызове dlopen() и оставляют его после вызова dlclose(); 2 библиотеки регистрируют обработчик SIGABRT при вызове dlopen().
Возможность совершения атаки продемонстрирована в предлагаемом по умолчании окружении Ubuntu (в других дистрибутивах не проверялось), в котором дополнительно установлены три пакета из репозитория “universe” (предполагается, что в некоторых дистрибутивах возможно проведение атаки в конфигурации по умолчанию). Всего предложено 8 вариантов совершения атаки. Например, один из вариантов, перспективных для создания рабочего эксплоита, основывается на том, что библиотека libgnatcoll_postgres.so при выполнении dlopen() регистрирует отдельный стек сигналов, используемый в обработчиках сигналов, через вызов функции sigaltstack(), а после вызова dlclose() убирает маппинг памяти, но не отключает регистрацию (SS_DISABLE) стека сигналов. Для эксплуатации уязвимости выполняются следующие манипуляции:
- Загружается несколько библиотек для изменения раскладки mmap.
- Загружается библиотека libgnatcoll_postgres.so, регистрирующая альтернативный стек сигналов и выполняющая munmap().
- Загружаются библиотеки для изменения раскладки mmap и замены откреплённого стека сигналов на другую область памяти в режиме записи (например, стек потоков или сегменты .data/.bss).
- Загружается библиотека, регистрирующая обработчик сигналов SA_ONSTACK, но не выполняющая для него munmap() при вызове dlclose().
- Загружается библиотека, получающая сигнал и вызывающая обработчик сигналов SA_ONSTACK, что приводит к перезаписи заменённой области памяти на кадры стека из обработчика сигналов.
- Загружаются библиотеки для определённой перезаписи содержимого заменённой области памяти.
Уязвимость устранена в опубликованном несколько часов назад выпуске OpenSSH 9.3p2. В новой версии по умолчанию запрещены запросы на загрузку модулей PKCS#11 (для разрешения теперь нужно указывать отдельный флаг “-Oallow-remote-pkcs11″). В качестве обходного пути защиты можно указать при запуске ssh-agent пустой белый список PKCS#11/FIDO (ssh-agent -P ”) или явно определить разрешённые библиотеки в белом списке.