
CVE-2026-6471에 대한 개념 증명 익스플로잇으로, PostgreSQL에서 논리적 디코딩 dlopen을 통한 권한 상승을 시연하여 임의 코드 실행 및 슈퍼유저 백도어를 달성합니다.
PostgreSQL의 논리적 디코딩(logical decoding)은 REPLICATION 권한을 보유한 비-슈퍼유저 역할이 논리적 복제 슬롯을 생성하고 출력 플러그인(output plugin)을 선택할 수 있게 합니다. 영향을 받는 버전에서는 해당 선택에 대한 권한 검사가 없으므로, 서버는 플러그인 이름이 가리키는 모든 것을 dlopen()합니다. 라이브러리 경로를 지정하면 해당 라이브러리의 코드가 서버를 실행하는 운영 체제 계정으로 postgres 백엔드 내부에서 실행됩니다. 이는 데이터베이스 서버의 OS 사용자로서의 임의 코드 실행을 의미하며, 애플리케이션 데이터를 보유한 데이터베이스의 경우 사실상 서버 장악(takeover)입니다.
PostgreSQL 18.6, 17.11, 16.15, 15.19 및 14.24에서 output_plugin_libraries 허용 목록(기본값 pgoutput, test_decoding)으로 수정되었습니다. 이 목록에 없는 항목은 이제 dlopen 이전에 library "X" may not be used as an output plugin 오류가 발생합니다.
두 빌드 모두에 동일한 단계를 실행하며 PostgreSQL 버전만 다릅니다. 낮은 권한의 계정(LOGIN + REPLICATION, 슈퍼유저 아님, OS 접근 권한 없음)이 일반적인 논리적 디코딩 구독자가 하는 작업을 수행한 다음, 서버에 임의 라이브러리를 출력 플러그인으로 로드하도록 요청합니다. 취약한 빌드에서는 해당 라이브러리가 postgres OS 사용자로 실행되어 영구적인 슈퍼유저 백도어 역할을 심으므로, 복제 전용 계정이 실행을 마치면 작동하는 슈퍼유저 로그인이 확보됩니다.
cve-2026-6471-postgres-logical-decoding-dlopen.txt는 Exploitmatic 솔루션(.txt)입니다: 데이터와 어서트(assert)만 포함하며 코드는 없습니다. 런타임이 이를 박스에 대해 재생합니다. 솔루션은 런타임에 pwn.so를 전달하고(파일 내 base64), 낮은 권한의 복제 역할로 SQL을 실행한 다음, 페이로드가 심은 슈퍼유저 백도어 역할로 로그인합니다.pwn.c는 페이로드 라이브러리 소스이고 pwn.so는 그 빌드 결과입니다: postgres OS 사용자로 실행되는 단일 ELF 생성자(constructor)로, 로컬 소켓을 통해 데이터베이스 슈퍼유저로 연결(peer/trust)하고 영구 역할 cve6471_backdoor LOGIN SUPERUSER PASSWORD 'BackdoorPass1'을 생성합니다. 서버가 실제로 라이브러리를 로드하는 경우에만 실행됩니다. 즉, 취약한 빌드에서만 실행됩니다. 서버 이미지와 일치하는 Linux libc에서 gcc -Os -shared -fPIC -o pwn.so pwn.c로 빌드합니다.전제 조건: docker 접근 권한이 있어야 합니다.
lab/ 폴더에는 이 PoC를 검증하는 데 사용된 정확한 복제본이 들어 있습니다. 두 박스(취약 = postgres 16.14, 패치 = postgres 16.15)를 빌드하고 실행합니다:
docker build -t pg-6471-vuln -f lab/Dockerfile.vuln lab
docker build -t pg-6471-fixed -f lab/Dockerfile.fixed lab
docker run -d --name pg-6471-vuln -p 15432:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-vuln
docker run -d --name pg-6471-fixed -p 15433:5432 -e POSTGRES_PASSWORD=lab-super-pw pg-6471-fixed
두 박스 모두 wal_level=logical로 공식 postgres 이미지를 실행합니다. 초기화 스크립트 lab/01-repro.sh는 솔루션이 사용하는 낮은 권한 역할 repro_rep LOGIN REPLICATION PASSWORD 'repropass'을 생성하며, 이는 슈퍼유저가 아닙니다.
그런 다음 솔루션을 재생합니다:
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1
파일 편집 없이 변수 재정의로 패치된 박스를 지정합니다:
exploitmatic run cve-2026-6471-postgres-logical-decoding-dlopen.txt 127.0.0.1 \
--var ctr=pg-6471-fixed
ctr는 docker 컨테이너이고, pw는 복제 역할의 비밀번호입니다.
| 대상 | 결과 |
|---|---|
| postgres 16.14 (취약), wal_level=logical | 4/4 검증됨, 슈퍼유저 백도어 로그인 작동 |
| postgres 16.15 (패치), wal_level=logical | 3/4 검증되지 않음, 백도어 없음 |
승인된 테스트 및 연구 목적으로만, 소유하거나 테스트 권한이 있는 시스템에서 사용하십시오. 이 PoC는 인증 후 권한 상승을 시연합니다: 기존의 REPLICATION 속성을 가진 낮은 권한 데이터베이스 계정과 postgres OS 사용자가 로드할 수 있는 위치에 공격자 제어 코드를 배치할 수단이 필요합니다. 원격 비인증 공격이 아닙니다. 로드된 코드가 데이터베이스 슈퍼유저에 도달하는 이유는 서버를 소유한 OS 계정이 로컬 소켓을 통해 슈퍼유저로 연결할 수 있기 때문이며(peer/trust), 이는 표준 PostgreSQL 배포 방식입니다.
| 단계 | 취약한 16.14 | 패치된 16.15 |
|---|
| 정찰(recon) (역할이 복제 전용, 슈퍼유저 아님) | 통과 | 통과 |
| 기준(baseline) (내장 pgoutput을 사용한 논리적 슬롯) | 통과 | 통과 |
| 트리거(trigger) (슬롯 플러그인 = 공격자 라이브러리 경로) | 서버가 로드함 | 로드 전에 거부됨 |
| 장악(takeover) (심어진 슈퍼유저 백도어로 로그인) | 슈퍼유저 | 해당 역할 없음 |