
Доказательство концепции, демонстрирующее обход авторизации в RegexRequestMatcher Spring Security (CVE-2022-22978) с использованием CRLF-инъекции, с анализом и шагами по смягчению.
Согласно полученной информации, это уязвимость, связанная с классом RegexRequestMatcher в фреймворке Spring Security. В частности, приложения, использующие RegexRequestMatcher, в регулярных выражениях которых содержится точка (.), могут быть обойдены с помощью символов \r(%0a) и \n(%0d); в результате злоумышленники могут получить доступ к запрещенным путям без аутентификации.
Затронутые версии фреймворка Spring Security:
5.5.x до 5.5.75.6.x до 5.6.4Нам нужно получить доступ к исходному коду Spring Security для статического анализа этой уязвимости. В частности, я использовал функцию сравнения коммитов между версиями 5.6.3 (уязвимая версия) и 5.6.4 (исправленная версия) на Github. Смотрите по ссылке: Comparing 5.6.3...5.6.4 · spring-projects/spring-security (github.com)

Я проверил изменения в классе RegexRequestMatcher. Видно, что в версии 5.6.4 этот класс использует Pattern.DOTALL вместо точки . по умолчанию, как в версии 5.6.3.
Где:
Pattern : один из трех классов в пакете java.util.regex, предназначенный для обработки регулярных выражений.Pattern.DOTALL : При использовании этого флага "." в регулярном выражении будет соответствовать любым символам, включая символы новой строки, такие как \n, \r.Pattern.CASE_INSENSITIVE: игнорирует регистр символов.
По умолчанию точка . в регулярном выражении соответствует всем символам, кроме символов новой строки, таких как \n, \r. В таком случае, если есть функция regex для проверки шаблона строки, она не будет соответствовать при наличии символов новой строки в строке. Чтобы избежать этого, можно использовать флаг Pattern.DOTALL.
Однако если кто-то намеренно использует %0d вместо \n или %0a вместо \r, то регулярное выражение всё равно не сработает. Поэтому в версии 5.6.4 была добавлена дополнительная проверка этого случая в RegexRequestMatcherTests.java. А именно, он преобразует %0d и %0a в \n и \r соответственно, а затем проверяет с помощью regex.

Шаг 1: Создайте веб-приложение Spring Boot с помощью Spring Initializr с двумя зависимостями: Spring Security и Spring Web.

Шаг 2: Создайте контроллер, который выводит текст This is a CVE-2022-22978 demo при запросе по пути /admin/*.

Шаг 3: Настройте механизм аутентификации при каждом доступе пользователя к пути /admin/<любой> с помощью regexMatchers("/admin/.*").authenticated(). Это и есть уязвимость, которую злоумышленники используют для просмотра содержимого страниц /admin/<любой> без аутентификации.

Шаг 4: В файле конфигурации укажите версию Spring Security, содержащую уязвимость. Здесь я выбрал версию 5.6.3.

Шаг 5: Запустите приложение командой gradlew bootRun, программа по умолчанию использует Apache Tomcat, который прослушивает порт 8080. Перейдите по пути /admin/xyz (любой путь, начинающийся с /admin/).

Результатом является код 403 Forbidden, что означает, что доступ невозможен из-за отсутствия аутентификации.
Теперь, используя уязвимость функции regexMatchers в Spring Security (версия 5.6.3), которая не соответствует символам новой строки, таким как \r(%0d) и \n(%0a), мы можем получить доступ к указанному пути без аутентификации с помощью полезной нагрузки /admin/%0dxyz.

Аналогично с нагрузкой /admin/%0axyz.

Таким образом, мы успешно использовали уязвимость CVE-2022-22978 с помощью очень простой полезной нагрузки.
5.7.1.
Попробуйте атаковать веб-приложение с помощью той же полезной нагрузки: /admin/%0dxyz.

На этот раз приложение не вернуло ответ, который ожидал злоумышленник.
git clone https://github.com/ducluongtran9121/CVE-2022-22978-PoC.git
cd CVE-2022-22978-PoC
gradlew bootRun
Java 18
Gradle 7.4.1