arm64e에서 수제 Mach-O 체인드 픽스업을 통해 dyld를 PAC 서명 오라클로 사용하여 제어된 PAC 유효 포인터 쓰기 및 iOS에서 디스패치 콜백 실행을 달성하는 PoC.
CVE-2026-20700과 관련하여, dyld의 페이지인 링킹 및 체인 고정 메커니즘을 PAC 서명 오라클로서 통제된 탐색.
arm64e에서는 모든 함수 포인터가 하드웨어 인증됩니다. 여기서의 목표는 dyld 자체를 조작된 Mach-O를 통해 지시하여, 자체 정상 고정 메커니즘만을 사용하여 공격자가 선택한 슬롯에 PAC 유효 포인터를 생성하도록 할 수 있음을 보여주는 것입니다.
테스트 환경: iPhone 14 (iOS 18.5, arm64e).
__DATA의 선택된 슬롯에 PAC 유효 함수 포인터를 기록합니다.fixupPage64에서 결정론적 크래시 — 잘못된 page_start / next 값으로 dyld가 페이지 경계를 벗어나도록 유도하여 분기 도달 가능성을 증명합니다.dispatch_source_t 타이머 핸들러로 등록되고, PoC 코드의 직접 호출 없이 이벤트 루프를 통해 자연스럽게 호출됩니다.dyld-signing-oracle-poc/
├── Makefile ← 전체 파이프라인 조율
├── src/
│ └── launcher.c ← iOS 런처 (2개 스레드 + 디스패치 체인 닫기)
├── generators/
│ ├── gen_exports.py ← exports.c 생성 (N개의 더미 심볼)
│ ├── gen_client.py ← client.c 생성 (N개의 임포트, dyld 게이트 스트레스)
│ └── gen_malformed_dylib.py ← libmalformed.dylib 생성 (조작된 Mach-O)
├── tools/
│ ├── scan_pointers.py ← Mach-O 포인터 섹션을 W/R로 분류
│ └── inspect_fixups.py ← LC_DYLD_CHAINED_FIXUPS 헤더 파싱
└── blog/
├── it/
│ └── dyld-signing-oracle.md ← 이탈리아어 전체 글
└── en/
└── dyld-signing-oracle.md ← 영어 전체 글
| 파일 | 생성자 |
|---|---|
exports.c | generators/gen_exports.py + Makefile sentinel symbols |
client.c | generators/gen_client.py |
libmalformed.dylib | generators/gen_malformed_dylib.py |
libexports.dylib | clang from exports.c |
libclient.dylib | clang from client.c |
PoCApp | clang from src/launcher.c |
PoCApp.ipa | Makefile package 단계 |
xcrun --sdk iphoneos --show-sdk-path)# 기본 전체 빌드 (arm64, 99k 심볼)
make
# 반복 작업을 위한 빠른 빌드
make SYMBOLS=10000
# fixupPage64에서 결정론적 크래시 (분기 도달 가능성 증명)
make stress
# 안정적인 이미지 내 쓰기-어디에-무엇을
make exploit
# dyld가 PAC 유효 포인터 기록 → 디스패치가 자연적으로 호출
make chain_close
# 생성된 체인 고정 블롭 레이아웃 확인
make verify
# libmalformed.dylib의 LC_DYLD_CHAINED_FIXUPS 헤더 파싱
make inspect
# 컴파일된 바이너리에서 포인터 섹션 (GOT/non-lazy) 스캔
make scan
| 변수 | 기본값 | 설명 |
|---|---|---|
SYMBOLS | 99000 | libclient의 바인드 대상 개수 (pre-26.3 게이트용 < 100k, 26.3+용 < 64k) |
STACK_KB | 128 | 작업자 스레드 스택 크기 (KB) |
BURN_KB | 0 | dlopen 전 소모할 스택 KB (0 = 자동) |
MARGIN_KB | 24 | 자동 소모 여유 |
ARM64E | 0 | DYLD_CHAINED_PTR_ARM64E_USERLAND24 형식 사용 |
MALFORM_PAGEIN | 0 | 잘못된 페이지인 체인 활성화 |
MALFORM_TARGET_OFFSET | — | __DATA 내 대상 오프셋 (예: 0x10) |
CHAIN_CLOSE | 0 | 두 번째 슬롯 → _attacker_hook, 디스패치 데모 활성화 |
# 애드혹 서명 (Sideloadly)
make chain_close
# PoCApp.ipa를 Sideloadly로 드래그
# 실제 인증서 사용
make resign IDENTITY="iPhone Developer: ..." PROFILE=embedded.mobileprovision
# 로그 모니터링
idevicesyslog | grep "POC"
PoCApp 내 런타임 로드 순서:
libexports.dylib — 가장 먼저 로드됨 (RTLD_GLOBAL), 이후의 dlopen에 write_target_value와 attacker_hook을 제공.libclient.dylib — 스레드 B에 의해 로드됨 (128KB 스택); 약 99k 바인드 대상이 dyld 페이지인 링킹 게이트에 스트레스를 줌.libmalformed.dylib — 스레드 A에 의해 로드됨; 조작된 체인 고정 체인이 dyld로 하여금 _write_target_value (및 선택적으로 _attacker_hook)를 __DATA+0x10 / +0x20에 해결하고 기록하게 함.chain_close 모드에서 메인은 __DATA+0x20을 dispatch_source_t 타이머 핸들러로 등록 — 이벤트 루프가 1초 후 PoC 코드의 직접 호출 없이 이를 호출.이탈리아어와 영어로 된 전체 기술 문서. 다루는 내용: PAC 하드웨어 메커니즘, 포인터 생성자로서의 dyld, 처음부터의 체인 고정 인코딩, 페이지인 링킹 게이트 메커니즘, Mach-O 엔지니어링 함정 (sizeofcmds, 섹션 개수, stride), 카나리 검증 데이터 레이아웃, 99k 심볼 게이트, 도달 가능성 증명 크래시, 안정적인 이미지 내 프리미티브, arm64e 서명 오라클 개념, 디스패치 타이머 체인 닫기.