Уязвимость BatBadBut, затрагивающая стандартные библиотеки различных языков программирования

Приложения, запускающие сценарии в формате bat и cmd на платформе Windows при помощи штатных функций запуска процессов, подвержены уязвимости, позволяющей добиться выполнения своего кода в случае передачи при запуске аргументов без отдельного экранирования спецсимволов. Уязвимость получила кодовое имя BatBadBut и проявляется в приложениях, использующих стандартные библиотеки таких языков, как Rust, PHP, Node.js, Python, Ruby, Go, Erlang и Haskell.

Проблема отмечена как уязвимость так как затрагивает функции библиотеки, такие как Command::arg и Command::args в Rust, рассчитанные на прямую передачу процессу аргументов, без их обработки командным интерпретатором. Подразумевается, что разработчик приложения может не проверять аргументы, так как они напрямую передаются запускаемому процессу. Если в Unix-системах аргументы передаются процессу по отдельности в массиве, то в Windows при использовании API CreateProcess аргументы оформляются в виде одной строки, разбор которой ложится на плечи запускаемого процесса.

При запуске bat- и cmd-сценариев на платформе Windows функция CreateProcess() неявно привлекает исполняемый файл cmd.exe, даже если приложение не указывает его при вызове. Программа cmd.exe содержит собственную сложную логику разделения аргументов для отделения собственных аргументов, запускаемого сценария и аргументов этого сценария. Для защиты от подстановки аргументов на платформе Windows в стандартных библиотеках применяется отдельные обработчики экранирования, которые оказалось можно обойти через манипуляцию с кавычками.

Например, в программе, вызывающей сценарий ‘./test.bat’ с аргументом на основе полученных от пользователя данных, атакующий может передать значение ‘»&calc.exe’, которое при запуске сценария будет развёрнуто в строку ‘C:WindowsSystem32cmd.exe /c .test.bat «»&calc.exe»‘ и приведёт к запуску процесса calc.exe. Метод действует и при неявном запуске сценариев, когда запускается исполняемый файл с именем «test» без указания расширения, а в одном из каталогов, упомянутых в переменной окружения PATHEXT, присутствует файл «test.bat».

В настоящее время исправление уже выпущено (CVE-2024-24576) для стандартной библиотеки языка Rust и вошло в состав обновления Rust 1.77.2. В процессе подготовки находятся обновления с устранением уязвимости для Node.js и PHP (уже выставлены теги 8.2.18 и 8.3.5, но релизы пока не объявлен). В проектах Python, Ruby, Go, Erlang и Haskell в документацию добавлено предупреждение о проявлении уязвимости при отсутствии должного экранирования спецсимволов.

В Rust 1.77.2 в стандартную библиотеку добавлена дополнительная проверка, возвращающая ошибку при наличии в аргументе запускаемого сценария спецсимволов, которое невозможно гарантированно безопасно экранировать. Для разработчиков, самостоятельно реализующих логику экранирования предоставлен метод CommandExt::raw_arg, полностью отключающий экранирование на стороне библиотечных вызовов.

Добавлению защиты мешает то, что простого экранирования двойных кавычек недостаточно, так как командный интерпретатор обрабатывает и раскрывает переменные, такие как «%PATH%». Например, кавычку можно подставить через манипуляцию с переменной окружения «%CMDCMDLINE%», указав вместо ‘»&calc.exe’ — ‘%CMDCMDLINE:~-1%&calc.exe’.

Источник: http://www.opennet.ru/opennews/art.shtml?num=60964