
CTF 스타일 Docker 랩 for CVE-2026-41651 (Pack2TheRoot): PackageKit의 허용적 polkit 로컬 권한 상승
PackageKit 데몬의 12년 된 취약점인 Pack2Theroot 권고(CVE-2026-41651)를 기반으로 한 Docker 기반 CTF 스타일 로컬 권한 상승 실습 랩입니다. 이 취약점은 Deutsche Telekom의 Red Team이 2026년 4월 22일에 공개한 PackageKit 데몬의 결함입니다.
이 랩은 세 개의 컨테이너로 구성됩니다: 허용적인 polkit CTF 챌린지, 강화된 비교 대상, 그리고 취약한 PackageKit을 소스에서 빌드하여 실제 CVE-2026-41651 근본 원인 익스플로잇을 실행하는 전체 TOCTOU 익스플로잇 재현입니다.
| 컨테이너 | 포트 | 역할 | 익스플로잇 결과 |
|---|---|---|---|
pack2theroot-vuln | tcp/2222 (ssh) | PackageKit ≤ 1.3.4 + 허용적 polkit 규칙 | 조작된 RPM을 통한 루트 |
pack2theroot-patched | tcp/2223 (ssh) | 동일하지만 polkit 강화됨 | 익스플로잇 실패 |
pack2theroot-exploit | — | 소스에서 빌드한 취약한 PackageKit 1.3.4 | TOCTOU D-Bus 레이스를 통한 루트 |
추가로:
docs/CHALLENGE.md)docs/HINTS.md)docs/SOLUTION.md)docs/diagrams/)pk-transaction.c의 세 가지 연쇄 버그익스플로잇은 동일한 트랜잭션에 두 개의 비동기 D-Bus InstallFiles() 호출을 보냅니다: 먼저 SIMULATE로 (polkit 우회, GLib idle 콜백 큐잉), 그런 다음 즉시 NONE + 악성 패키지로 (idle이 실행되기 전에 캐시된 플래그/경로를 덮어씀). GLib의 우선순위 순서는 두 D-Bus 메시지가 idle 콜백보다 먼저 디스패치되도록 보장합니다 — 따라서 타이밍 레이스가 아닌 결정적 동작입니다.
알려진 IOC (권고에서):
journalctl --no-pager -u packagekit | grep -iE 'emitted_finished|pk_transaction_finished_emit|pk-transaction\.c:514'
git clone https://github.com/dinosn/pack2theroot-lab.git
cd pack2theroot-lab
docker compose build
docker compose up -d
ssh labuser@localhost -p 2222 # 비밀번호: labuser
# 그런 다음 docs/CHALLENGE.md 작업 진행
플래그는 /root/flag.txt에 있습니다 (모드 0400 root:root). 형식:
PACK2THEROOT{...}
# 빌드 및 실행 — 자동 모드는 익스플로잇을 즉시 실행합니다:
docker compose run --rm exploit
# 또는 수동 모드:
docker compose run --rm --entrypoint /entrypoint.sh exploit
# 그런 다음 컨테이너 내부에서:
su - victim -c /exploit/cve-2026-41651
익스플로잇은 C로 두 개의 .deb 패키지를 빌드하고 (외부 도구 불필요), 두 호출 D-Bus 레이스를 보내며, /tmp/.suid_bash에 SUID bash를 생성합니다. 전체 기술 워크스루는 docs/SOLUTION.md를 참조하세요.
정리:
docker compose down -v
pack2theroot-lab/
├── README.md
├── docker-compose.yml
├── docs/
│ ├── CHALLENGE.md # 플레이어 브리프
│ ├── HINTS.md # 단계별 힌트 (두 경로 모두)
│ ├── SOLUTION.md # 전체 워크스루 + 플래그
│ ├── references.md # 1차 및 2차 출처
│ ├── threat-model.md # 공격자/방어자 가정
│ └── diagrams/ # 익스플로잇 흐름의 SVG 시각적 다이어그램
│ ├── 01-docker-build.svg
│ ├── 02-container-startup.svg
│ ├── 03-exploit-execution.svg
│ ├── 04-dbus-race-sequence.svg
│ ├── 05-attack-overview.svg
│ └── 06-auto-mode-full-run.svg
├── exploit/
│ ├── Dockerfile # 취약한 PackageKit 1.3.4를 소스에서 빌드
│ ├── entrypoint.sh # dbus + polkitd + packagekitd 시작
│ ├── Makefile
│ └── src/
│ └── cve-2026-41651.c # TOCTOU 익스플로잇 (공개 PoC)
├── vulnerable/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── policy/
│ └── 10-pack2theroot-lab-misconfig.rules # CTF 챌린지
├── patched/
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── local/ # 1.3.5 백포트 RPM을 여기에 배치 (선택 사항)
│ └── policy/
│ └── 10-pack2theroot-lab-hardened.rules # 수정 사항
└── scripts/
├── exploit-check.sh # 버전, polkit, D-Bus, IOC 확인
├── check-version.sh # VULNERABLE vs PATCHED 판정
├── check-preconditions.sh # pkcon / polkit / D-Bus 정상 동작 확인
├── monitor-ioc.sh # 권고 IOC에 대한 저널 tail
├── compare-env.sh # 두 컨테이너 diff
└── apply-polkit-mitigation.sh # 패치되지 않은 호스트용 임시 강화
docs/diagrams/ 디렉토리에는 익스플로잇 흐름을 보여주는 SVG 다이어그램이 있습니다. 브라우저에서 열면 됩니다:
docs/CHALLENGE.md를 참조하세요. 요약:
labuser로 SSH 접속 (비밀번호 labuser).rpm-build, rpmdevtools가 설치되어 있음).pkcon install-local --allow-untrusted로 설치.%post 스크립틀릿이 루트로 실행됩니다. /root/flag.txt를 읽으세요.막혔나요? docs/HINTS.md에 점점 더 명시적인 힌트가 있습니다. 문제를 해결했거나 정말로 라이트업이 필요할 때만 docs/SOLUTION.md를 여세요.
두 컨테이너 내부에서, 모든 사용자로:
/opt/lab/check-version.sh # VULNERABLE 또는 PATCHED 판정
/opt/lab/check-preconditions.sh # 노출 자가 진단
/opt/lab/exploit-check.sh # 버전 + polkit + D-Bus + IOC 확인
/opt/lab/monitor-ioc.sh # IOC에 대한 저널 tail
호스트에서 나란히 비교:
./scripts/compare-env.sh
취약한 컨테이너에 임시 polkit 완화 적용:
docker exec pack2theroot-vuln /opt/lab/apply-polkit-mitigation.sh
# 그런 다음 익스플로잇 재시도 — 이제 실패해야 합니다.
patched 이미지는 PackageKit 버전 상태를 정직하게 처리합니다:
/etc/pack2theroot-banner)를 표시합니다.배포판이 백포트를 게시한 후 버전이 완전한 패치 이미지를 빌드하려면 RPM을 patched/local/에 넣고 다시 빌드하세요:
docker compose build --build-arg USE_LOCAL_RPM=1 patched
--privileged가 필요합니다. 격리된 환경에서만 실행하세요.labuser)는 의도적으로 약합니다. 절대 재사용하지 마세요.1차 출처:
CVE-2026-41651:
https://nvd.nist.gov/vuln/detail/CVE-2026-4165176cfb675:
https://github.com/PackageKit/PackageKit/commit/76cfb675fb31acc3ad5595d4380bfff56d2a86972차 보도 및 배포판 추적기는 docs/references.md를 참조하세요.
MIT — LICENSE 참조.
| 필드 | 값 |
|---|
| CVE | CVE-2026-41651 |
| 이름 | Pack2TheRoot |
| 클래스 | 로컬 권한 상승 (TOCTOU / CWE-367) |
| 구성 요소 | PackageKit 데몬 (pk-transaction.c) |
| 취약 범위 | >= 1.0.2 및 <= 1.3.4 (12년간의 릴리스) |
| 수정 버전 | PackageKit 1.3.5 (커밋 76cfb675, 2026-04-22 릴리스) |
| CVSS 3.1 | 8.8 (HIGH) — AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
| 사전 조건 | PackageKit을 실행하는 호스트의 로컬 비특권 셸 |
| 발견자 | Deutsche Telekom Security GmbH — Red Team |
| 버그 | 위치 | 영향 |
|---|
| BUG 1 | InstallFiles() (~라인 4036) | cached_transaction_flags 및 cached_full_paths를 무조건 덮어씀 — 상태 가드 없음 |
| BUG 2 | pk_transaction_set_state() (~라인 876–881) | 오류를 발생시키는 대신 역방향 상태 전환을 조용히 버림 — 플래그가 이미 오염됨 |
| BUG 3 | pk_transaction_run() (~라인 2273–2277) | 인증 시점이 아닌 디스패치 시점에 cached_transaction_flags를 읽음 |
| 우회 | SIMULATE 플래그 (~라인 2893–2900) | PK_TRANSACTION_FLAG_SIMULATE (0x4)가 polkit을 완전히 우회함 |
| 다이어그램 | 설명 |
|---|
01-docker-build.svg | 2단계 Docker 빌드 — 취약한 PackageKit 컴파일 |
02-container-startup.svg | 컨테이너 시작 — dbus, polkitd, packagekitd 시작 |
03-exploit-execution.svg | 주석이 달린 단계별 익스플로잇 출력 |
04-dbus-race-sequence.svg | D-Bus 시퀀스 다이어그램 — BUG 1/2/3이 GLib 우선순위와 어떻게 연결되는지 |
05-attack-overview.svg | 높은 수준의 공격 흐름: 타임라인이 있는 공격자 vs 시스템 |
06-auto-mode-full-run.svg | 완전한 --auto 모드 터미널 — 컨테이너 시작부터 루트 셸까지 |