Построение CVE-2025-0282 в Ivanti Connect Secure
Исследователями из Watchtowr опубликовано подробное описание того, как обнаружили возможность и реализовали удалённое исполнение кода (RCE) в свежей CVE-2025-0282 (Ivanti Connect Secure – это, как нередко случается, корпоративный продукт для “защищенного корпоративного VPN”).
Описание по ссылке выше – довольно техническое, требует специальных знаний для понимания. Если кратко, то основой данной уязвимости является типовое переполнение буфера из-за перепутанных в исходном коде значений максимального размера массива, но вот для успешной реализации – потребовались не самые прямолинейные техники.
Как справедливо замечают в тексте описания исследователи, исходную ошибку, приводящую к переполнению буфера, смог бы обнаружить даже простой статический анализатор кода. Но, в принципе, понятно, почему статический анализатор не был здесь должным образом использован компанией-разработчиком. Дело в том, что применение таких инструментов не на бумаге требует высокой квалификации от применяющего, так как сам по себе стат. анализатор мало что даёт – ещё нужен редкий специалист, понимающий, что именно происходит, с разных сторон: со стороны ИБ, со стороны устройства компиляторов и разработки ПО, со стороны устройства аппаратуры и практики “сетевых технологий”, и т.д. Ещё один пример, показывающий, что так называемая “безопасная разработка”, как принцип, в целом, интересна, но практическое значение соответствующих инструментов в корпоративной среде сильно преувеличено. Впрочем, вернёмся к описанию уязвимости.
Прямолинейной эксплуатации через перезаписывание стека помешало наличие в этом стеке указателя на блок памяти, который должен был освобождаться перед возвратом из атакуемой функции (то есть, вызов конструкции с free() приводил бы к преждевременному возникновению исключения). Но исследователи смогли найти точку модификации таблицы Vtable, которая содержит указатели на функции (это типовая конструкция для “виртуализации” “методов” в C++), а потом ещё успешно нашли в коде гаджет*, модифицирующий указатель стека. Причём, поиск гаджета был затруднён тем, что требовалось найти точку для входа, которая совпадала бы не только по подобранному значению указателя, но и по значению смещения, жёстко зафиксированного в исполняемом коде. А это стало возможно потому, что исследуемое приложение использует много библиотек: “It’s a good thing that the Ivanti web binary contains so many libraries”. Как говорится, принцип разработки с созданием минималистичного и простого собственного кода мог бы здесь помочь. Ну, раз не помог стат. анализатор.
* – дополнение от 13.01.2025: гаджет – фрагмент машинного кода с нужными свойствами, оканчивающийся командой передачи управления, см. комментарии к записке.
Адрес записки: https://dxdt.ru/2025/01/12/14750/
Похожие записки:
- Неверные обобщения "принципа Керкгоффса"
- Реплика: TLS-сертификаты для IP и DoT
- Статья про DNS-измерения в Сети (2020)
- Занятный замок Fichet 787
- Название для ML-KEM на русском
- Новые атаки на SHA-256 (SHA-2): технические пояснения
- Публикации в журналах, 2024
- Про цепочки, RSA и ECDSA
- Вывод ключей Kyber768 на tls13.1d.pw
- Помехи GNSS и распределённые "геосервисы"
- Сдвиги времени в сертификатах Let's Encrypt
Комментарии читателей блога: 2
1 <t> // 13th January 2025, 09:55 // Читатель Alena написал:
Что значит слово “гаджет” применительно к программному (или машинному?) коду?
Я знаю, что это такое, если речь идёт о физическом устройстве.
2 <t> // 13th January 2025, 10:26 // Александр Венедюхин:
“Гаджет” здесь – это кусок машинного кода, содержащий команды, нужные для выполнения конкретного элементарного действия, и заканчивающийся, обычно, либо командой возврата из подпрограммы по адресу из стека (RET), либо командой безусловного перехода (JMP) по заданному адресу (смещению). Грубо говоря, для того, чтобы реализовать какой-то алгоритм, осуществляется последовательный вызов набора “гаджетов”, найденных в исполняемом коде на атакуемой системе: то есть, скажем, настроили нужную последовательность в стеке – передаём управление на входной “гаджет” через штатный RET программы, и дальше процессор последовательность выполняет, переходя между “гаджетами” по заготовленным в стеке адресам (это называется ROP – Return-Oriented Programming).
Вот тут есть некоторые примеры: https://dxdt.ru/2024/02/20/12409/
Написать комментарий