
macOS PackageKit 심볼릭 링크 추적 버그(CVE-2026-28912)에 대한 리버스 엔지니어링 노트와 동작하는 PoC, 그리고 26.6 수정 버전의 디스어셈블리 diff를 포함합니다.
macOS PackageKit 심볼릭 링크 추적 버그(CVE-2026-28912)에 대한 독립적인 리버스 엔지니어링과, 설치 프로그램이 설치 대상 경로의 디렉터리 심볼릭 링크를 통해 공격자가 제어하는 파일을 root 권한으로 기록하는 것을 보여주는 동작하는 PoC입니다.
이 버그는 PKCoreShove의 파일 재링크 로직에서 발생하는 동기화되지 않은 경로 순회입니다. 악성 .pkg는 비권한 디렉터리에 대상 경로를 선언하고, 경로 구성 요소 중 하나에 권한이 있는 위치를 가리키는 디렉터리 심볼릭 링크를 배치하여 root로 실행되는 설치 프로그램이 심볼릭 링크 대상에 기록하도록 만들 수 있습니다. Apple의 26.6 수정은 각 경로 구성 요소를 O_NOFOLLOW로 순회하고 모든 심볼릭 링크를 거부하는 _PKSIPOpenPathSafely를 추가합니다.
| 필드 | 값 |
|---|---|
| CVE | CVE-2026-28912 |
| 구성 요소 | PackageKit (PKCoreShove, PKBundleComponent) |
| 영향 받는 버전 | macOS Tahoe 26.5 및 이전 |
| 패치 버전 | macOS Tahoe 26.6 |
| 권고 영향 | "앱이 root 권한을 얻을 수 있습니다." |
| CVSS v3.1 | 7.8 (높음) |
| 보고자 | Apple 권고에 따른 원래 발견자 |
CVE-2026-28912에 대한 Apple의 권고는 영향과 패치된 버전을 문서화합니다. 하지만 기술적 메커니즘은 문서화하지 않습니다:
작성 시점에 공개된 기술 문서는 발견되지 않았습니다. 이 저장소는 26.4와 26.6 사이의 PackageKit에 대한 독립적인 리버스 엔지니어링 분석과 프리미티브를 실제로 보여주는 동작하는 PoC로 그 공백을 채웁니다.
이것은 발견 주장이 아닙니다. CVE는 원래 발견자에 의해 보고되었고 Apple에 의해 패치되었습니다. 여기서의 기여는 기술적 분석과 재현입니다.
macOS 26.4의 PKCoreShove _relinkFile:dest:는 파일을 생성할 때 대상 경로를 구성 요소별로 순회합니다:
; macOS 26.4, PackageKit
1a9fb14f8 _relinkFile:dest:
...
bl _linkResolutionProhibitted ; returns 0 in the normal case
mov w8, 0x10 ; RENAME_NOFOLLOW_ANY
cmp w0, 0
csel w22, w8, wzr, ne ; w22 = 0x10 if prohibited, else 0
...
mov x2, x22
bl _renamex_np ; uses w22 as flags
_linkResolutionProhibitted는 호출 프로세스가 SIP 파일을 수정할 수 없을 때 0(false)을 반환합니다 — 사용자가 시작한 설치의 일반적인 경우입니다. 이는 RENAME_NOFOLLOW_ANY를 비활성화하므로, rename이 대상 경로의 모든 심볼릭 링크를 추적합니다.
26.6 수정은 PKBundleComponent initWithBundleAtPath:relativeToDestination:에서 호출되는 _PKSIPOpenPathSafely를 추가합니다:
; macOS 26.6, PackageKit
1aa6dfe18 bl _PKSIPOpenPathSafely ; walks each component with O_NOFOLLOW
_PKSIPOpenPathSafely:
의도된 경로 외부를 가리키는 심볼릭 링크인 모든 구성 요소는 EPERM 또는 ELOOP로 거부되고 설치가 실패합니다.
전체 문서는 docs/ANALYSIS.md를, 주소와 로그 샘플은 docs/ARTIFACTS.md를 참조하세요.
link.sh — 단일 파일의 자체 포함 PoC:
시연된 영향은 심볼릭 링크 추적 프리미티브입니다 — 26.6 수정이 닫는 정확한 동작입니다.
PoC는 전적으로 대상에서 실행됩니다. 심볼릭 링크와 페이로드 모두 로컬에서 생성됩니다. 이는 네트워크 구성 없이 PoC를 자체 포함적이고 재현 가능하게 유지합니다.
chmod +x link.sh
./link.sh
환경 변수를 통한 선택적 조정:
sudo CONTENT="test content" ./link.sh
CONTENT는 심볼릭 링크를 통해 기록되는 내용을 설정합니다. 기본값은 hello입니다.
[*] System information:
ProductName: macOS
ProductVersion: 26.4
BuildVersion: 25E246
[*] Setup...
Symlink: /Users/nerd/cve-poc/target → /Users/nerd/cve-poc/real
[*] Build .pkg...
Payload: /Users/nerd/cve-poc/payload/Users/nerd/cve-poc/target/poc.txt
Package: /Users/nerd/cve-poc/poc.pkg
[*] Install (password prompt expected)...
installer: Package name is poc
installer: Installing at base path /
installer: The install was successful.
[✓] VULNERABILITY CONFIRMED
Landed at /Users/nerd/cve-poc/real/poc.txt
Owner: root:wheel
Content: hello
CVE-2026-28912 trigger SUCCESSFUL
패치된 시스템(26.6)에서는 동일한 PoC가 실패합니다:
[✗] Not triggered
No file was created in /Users/nerd/cve-poc/real/
디스어셈블리 비교는 docs/PATCH_DIFF.md를 참조하세요.
PoC의 두 가지 세부 사항은 개발 중에 발견되었으며, 유사한 도구를 만드는 다른 사람들이 같은 문제를 겪지 않도록 여기에 문서화합니다:
심볼릭 링크는 설치 프로그램이 순회하는 경로 구성 요소에 있어야 합니다. 대상 리프의 파일 수준 심볼릭 링크는 renamex_np에 의해 대체됩니다; 경로 중간의 디렉터리 심볼릭 링크만 추적됩니다.
페이로드 경로는 대상 경로를 반영해야 합니다. pkgbuild --install-location /를 사용하면 페이로드 경로는 선행 /를 제거한 대상 경로입니다. 일치하지 않으면 설치 프로그램이 심볼릭 링크를 통해 순회하지 않습니다.
둘 다 docs/ANALYSIS.md에 문서화되어 있습니다.
CVE-2026-28912는 설치 프로그램을 root로 실행하기 위해 사용자의 비밀번호가 필요합니다. 그 비밀번호는 설치를 위한 것이지 심볼릭 링크 기록을 위한 것이 아닙니다. 사용자는 $HOME/cve-poc/target/에 기록하는 것을 승인하고, 취약점은 기록을 심볼릭 링크가 가리키는 대상으로 리디렉션합니다. 두 경로는 다르며, 사용자는 그 차이를 결코 보지 못합니다.
이 저장소는 방어적 보안 연구 및 교육 목적으로만 제공됩니다.
MIT. LICENSE를 참조하세요.