
PackageKit의 TOCTOU 경쟁 조건을 통한 로컬 권한 상승.
CVSS 3.x : 7.8 HIGH
CWE : CWE-367 (Time-of-Check Time-of-Use)
Fix : PackageKit 1.3.5+
Affects : PackageKit 1.0.2 – 1.3.4
PackageKit의 D-Bus 트랜잭션 핸들러에서 TOCTOU 레이스 컨디션을 통한 로컬 권한 상승입니다.
권한이 없는 모든 로컬 사용자는 로컬 세션 외에 추가 인증 없이 루트 권한으로 임의의 패키지를 설치할 수 있습니다.
랩 / 승인된 테스트 전용 (HTB, CTF, 서면 범위가 명시된 작업).
python3 exploit.py
이게 전부입니다. /tmp/.suid_bash를 드롭한 다음 exec로 루트 셸에 진입합니다.
사용자 지정 SUID 경로 또는 타임아웃:
SUID_BIN=/dev/shm/.sh TIMEOUT=90 python3 exploit.py
apt install python3-gi dpkg-dev
이 익스플로잇은 런타임에 두 개의 .deb 패키지를 빌드합니다 — 컴파일러가 필요 없습니다.
src/pk-transaction.c의 세 가지 버그가 연쇄적으로 연결됩니다:
InstallFiles()는 상태 확인 없이 cached_transaction_flags와 cached_full_paths를 덮어씁니다. 동일한 트랜잭션에 대한 두 번째 D-Bus 호출은 트랜잭션이 이미 실행 중이더라도 이를 맹목적으로 교체합니다.
pk_transaction_set_state()는 불법적인 역방향 전이(RUNNING→READY 등)를 거부하지만 버그 1에서 덮어쓴 플래그는 롤백하지 않습니다. 손상된 플래그는 그대로 유지됩니다.
pk_transaction_run()은 인증 시점이 아니라 디스패치 시점(GLib idle)에 cached_transaction_flags를 읽습니다. 백엔드는 공격자의 플래그를 보게 됩니다.
PK_TRANSACTION_FLAG_SIMULATE(0x4)를 설정하면 polkit 인증 확인을 완전히 건너뜁니다. 호출 1은 사용자 상호 작용 없이 인증됩니다.
Attacker packagekitd
│ │
│ CreateTransaction() │ state = NEW
│─────────────────────────────────►│
│ │
│ InstallFiles(SIMULATE, dummy) │ polkit skipped (SIMULATE)
│─────────────────────────────────►│ state = READY, idle queued
│ │
│ InstallFiles(NONE, payload) │ flags+paths overwritten
│─────────────────────────────────►│ set_state(WAITING_FOR_AUTH) rejected
│ │ state stays READY (BUG 2)
│ │
│ [idle fires]│
│ │ pk_transaction_run() reads NONE (BUG 3)
│ │ → dpkg installs payload as root
│ │ → postinst: chmod +s /tmp/.suid_bash
│ │
│ execv("/tmp/.suid_bash -p") │
│─────────────────────────────────►│ euid=0(root)
두 호출 모두 GLib idle이 발생하기 전에 도착하므로 — 레이스에서 이길 필요가 없으며, 결정적입니다.
Ubuntu Desktop 18.04–26.04, Debian Trixie, Fedora 43, RockyLinux 10.1 및 데몬이 활성화된 상태로 PackageKit 1.0.2–1.3.4를 제공하는 모든 배포판.
systemctl mask packagekittransaction->state != PK_TRANSACTION_STATE_NEW → 거부