Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
cve-2026-43687 — macOS NFS 클라이언트 access-cache 레이스(CVE-2026-43687)에 대한 리버스 엔지니어링 노트와 자체 포함 PoC로, kext 디스어셈블리 diff 및 dtrace 레이스 캡처를 포함합니다. | Kitploit
도구/GitHubGitHub/jvidhan/cve-2026-43687
Memory ForensicsVulnerability AnalysisExploitationReverse EngineeringBinary AnalysisPapers & ResearchLearning & Education
GitHubjvidhan/cve-2026-43687

cve-2026-43687

macOS NFS 클라이언트 access-cache 레이스(CVE-2026-43687)에 대한 리버스 엔지니어링 노트와 자체 포함 PoC로, kext 디스어셈블리 diff 및 dtrace 레이스 캡처를 포함합니다.

저장소 보기
410시간 16분 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-43687 — 리버스 엔지니어링 노트 및 재현

macOS NFS 클라이언트 액세스 캐시 경쟁 조건(CVE-2026-43687)에 대한 독립적인 리버스 엔지니어링과, 해당 경쟁 조건을 트리거하고 dtrace로 실시간으로 포착하는 동작하는 PoC입니다.

이 버그는 _nfs_vnop_access에서 nfsnode 액세스 캐시 포인터를 동기화 없이 읽는 문제입니다. 악의적인 NFSv3 서버는 다른 스레드가 액세스 캐시를 읽는 동안 재할당하도록 유도할 수 있으며, 이로 인해 악의적인 서버가 영향을 줄 수 있는 커널 메모리 노출이 발생합니다. macOS 26.7은 nfsnode+0x158에 lck_rw_t를 삽입하고 캐시 읽기 주변에서 이를 공유 모드로 획득하여 이 문제를 수정합니다.


CVE 개요

필드값
CVECVE-2026-43687
구성 요소com.apple.filesystems.nfs (_nfs_vnop_access)
영향 받는 버전macOS Tahoe 26.6 및 이전, iOS 26.x 및 이전
패치된 버전macOS Tahoe 26.7, macOS Golden Gate 27, iOS 26.7, iOS 27
권고 영향"악의적인 NFS 서버에 연결하면 커널 메모리가 노출될 수 있습니다."
CVSS v3.16.5 (Medium) — AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
보고자KRsecurity의 R4mbb 및 Peter Malone (Apple 권고 기준)

이 문서가 존재하는 이유

CVE-2026-43687에 대한 Apple의 권고는 영향과 패치 버전을 문서화합니다. 하지만 기술적 메커니즘은 문서화하지 않습니다:

  • nfsnode의 어떤 필드가 경쟁 조건에 노출되는지
  • 두 번째 읽기가 어디에서 발생하는지
  • 수정이 왜 그 특정 오프셋에 잠금을 삽입하는지
  • PoC가 왜 stat(2)가 아닌 access(2)를 사용해야 하는지
  • 왜 일부 NFSv3 응답 형태가 와이어 포맷이 거의 정확함에도 불구하고 마운트를 조용히 깨뜨리는지

작성 시점에 공개된 기술 문서는 발견되지 않았습니다. 이 저장소는 26.6과 26.7 사이의 NFS kext에 대한 독립적인 리버스 엔지니어링 분석과, 실제 대상에서 경쟁 조건을 재현하는 동작하는 PoC로 이 공백을 채웁니다.

이것은 발견 주장이 아닙니다. 이 CVE는 R4mbb와 Peter Malone에 의해 보고되었고 Apple에 의해 패치되었습니다. 여기서의 기여는 기술적 분석과 재현입니다.


취약점 요약

NFS 클라이언트의 _nfs_vnop_access는 per-UID 액세스 캐시 배열에 대한 포인터인 nfsnode+0x158을 단일 호출 내에서 두 번 읽으며, 어떤 잠금도 보유하지 않습니다:

root@kitploit:~
; macOS 26.6, com.apple.filesystems.nfs
fffffe000b52def4   ldr  w8,  [x20, #0x160]     ; count
fffffe000b52def8   cmp  w23, w8
fffffe000b52defc   b.ge ...
fffffe000b52df00   ldr  x8,  [x20, #0x158]     ; cache ptr (read #1)
...
fffffe000b52df98   ldr  x8,  [x20, #0x158]     ; cache ptr (read #2)
fffffe000b52dfb0   ldr  w21, [x9]              ; dereference

기록자(writer)인 _nfs_nget는 클라이언트가 서버로부터 새로운 UID를 볼 때마다 kalloc_data로 배열을 재할당하고 결과를 +0x158에 저장합니다:

root@kitploit:~
fffffe000b52100c   bl   0xfffffe000b6a1dd8    ; kalloc
fffffe000b521010   str  x0,  [x22, #0x158]    ; cache ptr
fffffe000b521018   str  w20, [x22, #0x160]    ; cache count

다른 스레드가 리더의 두 로드 사이에 동일한 nfsnode에서 _nfs_nget에 도달하면, 두 번째 로드는 새 포인터를 반환하지만 첫 번째 읽기 — 이미 오프셋을 계산하는 데 사용된 — 는 이전 포인터를 기반으로 했습니다. 이후의 역참조는 해제된 커널 힙에서 읽습니다.

26.7 수정:

root@kitploit:~
fffffe000b9e3064   str  x0,  [x22, #0x168]    ; cache ptr moved
fffffe000b9e306c   str  w28, [x22, #0x170]    ; cache count moved
fffffe000b9e307c   add  x0,  x22, #0x158      ; lock slot
fffffe000b9e3084   bl   _lck_rw_init          ; init RW lock

그리고 _nfs_vnop_access에서:

root@kitploit:~
fffffe000b9f0200   add  x0,  x20, #0x158
fffffe000b9f0204   bl   _lck_rw_lock_shared    ; take the lock
fffffe000b9f0208   ldr  x9,  [x20, #0x168]    ; cache pointer
...
fffffe000b9f0230   bl   _lck_rw_unlock_shared  ; release the lock

구조체 레이아웃 변경:


이 저장소에 포함된 내용

리버스 엔지니어링

  • 26.6과 26.7 NFS kext 사이의 _nfs_nget 및 _nfs_vnop_access의 디스어셈블리 diff — docs/PATCH_DIFF.md 참조
  • 경쟁 조건에 노출된 필드 식별: 26.6의 nfsnode+0x158
  • 수정 사항 식별: +0x158에 lck_rw_t 삽입, 캐시 포인터를 +0x168로 이동, 읽기 주변에서 lck_rw_lock_shared 획득
  • 시스템 콜 분석: access(2)는 _nfs_vnop_access로 진입하고, stat(2)는 _nfs_getattr를 거쳐 취약한 함수에 도달하지 않음
  • dtrace를 통한 경쟁 조건의 런타임 확인, 호출 중간에 캐시 포인터가 변경되는 것을 포착

전체 문서는 docs/ANALYSIS.md를, 주소와 로그 샘플은 docs/ARTIFACTS.md를 참조하세요.

재현

  • poc.sh — 단일 파일의 자체 포함 PoC:
    1. 포트 2049를 확보하기 위해 Apple의 nfsd를 중지
    2. 모든 응답에서 보고되는 UID를 순환시키는 악의적인 NFSv3 서버를 127.0.0.1에서 시작
    3. noac로 새 마운트포인트에 익스포트를 마운트
    4. test -r / test -w를 통해 access(2)를 발행하는 per-user 해머를 생성
    5. nfs_vnop_access에 dtrace 프로브를 연결하여 호출 중간에 nfsnode+0x158이 변경되는 모든 호출을 기록
    6. 경쟁 조건 횟수를 포함한 요약을 출력

이 PoC가 입증하는 것

  • 모든 응답에서 보고하는 UID를 순환시키는 악의적인 NFSv3 서버
  • 이에 대응하여 피해자의 커널이 액세스 캐시 배열을 재할당하는 것
  • _nfs_vnop_access의 동기화되지 않은 읽기가 단일 호출 중에 배열 변경을 관찰하는 것
  • dtrace를 통한 해당 인터리빙의 실시간 포착

이 PoC가 입증하지 않는 것

  • 공격자에게 보이는 바이트 수준의 커널 메모리 누출
  • 코드 실행, 권한 상승, 또는 피해자에 대한 셸

경쟁 조건은 노출의 전제 조건입니다. 경쟁 조건을 실제 누출로 전환하려면 공격자는 리더가 오래된 포인터를 사용하는 것을 관찰하고 해당 바이트를 읽을 수 있는 곳으로 전파해야 합니다. arm64e에서 nfsnode+0x158의 값은 PAC 서명되어 있고 부팅별 키는 사용자 영역에서 사용할 수 없으므로, dtrace만으로는 경쟁 조건을 관찰할 수 있지만 포인터를 디코딩할 수는 없습니다. docs/ANALYSIS.md의 "Paths tested and ruled out" 섹션을 참조하세요.

입증된 영향은 경쟁 조건 자체 — 26.7 RW-잠금 수정이 닫는 정확한 윈도우입니다.


요구 사항

대상(피해자) 호스트

  • macOS 26.6 또는 이전 (취약한 커널)
  • dtrace 사용 가능 (일부 설치에서는 SIP 조정이 필요할 수 있음)
  • python3, dscl, mount
  • Root

별도의 공격자 호스트 불필요

PoC는 전적으로 대상에서 실행됩니다. 악의적인 NFS 서버는 127.0.0.1에 바인딩되고 마운트는 루프백을 통해 이루어집니다. 이는 네트워크 구성 없이 PoC를 자체 포함적이고 재현 가능하게 유지합니다.


사용법

root@kitploit:~
chmod +x poc.sh
sudo ./poc.sh

환경 변수를 통한 선택적 튜닝:

root@kitploit:~
sudo HAMMER_COUNT=30 RUN_SECONDS=600 ./poc.sh

HAMMER_COUNT는 per-user 해머 스레드 수를 설정합니다 (존재하는 nfsuserNNN 계정을 사용하고, 필요에 따라 생성합니다). RUN_SECONDS는 dtrace 윈도우를 설정합니다.

예상 출력

root@kitploit:~
[*] ensuring nfsuser accounts exist (UID 201..240)
    nfsuser accounts available: 12
[*] starting evil NFS server on 127.0.0.1:2049
[*] mounting /Users/Shared/nfs_test (with noac)
    mount check: hello.txt statable
[*] spawning up to 12 per-user threads + 1 root loop
    started 12 user threads + 1 root loop
[*] running dtrace for 180s — looking for RACE lines
[*] stopping dtrace
[*] cleaning up

=================== SUMMARY ===================
RACE events caught: 16

Vulnerable interleaving observed — sample:
RACE nd=fffffe5f53cbb940 in=(0,0) out=(b0967e0023297878,0)
RACE nd=fffffe5f534db940 in=(0,0) out=(84dd7e0023297878,0)
RACE nd=fffffe5f53cbb940 in=(0,0) out=(c9a37e0023297878,0)
RACE nd=fffffe5f538ab940 in=(0,0) out=(1867e0023297878,0)
RACE nd=fffffe5f539db940 in=(0,0) out=(149bfe0023297878,0)

CVE-2026-43687 trigger SUCCESSFUL
===============================================

각 RACE 줄은 액세스 캐시 포인터가 호출 중간에 변경된 nfs_vnop_access의 한 호출입니다.

패치 검증

패치된 시스템(26.7 / 27)에서는 동일한 워크로드가 RACE 이벤트를 0건 생성합니다. 디스어셈블리 비교는 docs/PATCH_DIFF.md를 참조하세요.


NFSv3 서버 주의사항 (재현성 관련)

PoC 서버의 두 가지 버그가 개발 중에 수정되었으며, 유사한 도구를 만드는 다른 사람들이 같은 문제를 겪지 않도록 여기에 문서화합니다:

  1. ACCESS3resok는 fattr3가 아닌 post_op_attr를 요구합니다. RFC 1813은 응답을 post_op_attr obj_attributes; uint32 access;로 정의합니다. post_op_attr는 fattr3 앞에 bool 접두사를 포함합니다. 이 bool을 생략하면 응답이 4바이트 짧아지고, 클라이언트는 이를 조용히 거부하며 마운트는 사용 가능해지지 않습니다.

  2. AppleDouble 이름(._*)에 대한 LOOKUP은 NFS3ERR_STALE(70)이 아닌 NFS3ERR_NOENT(2)를 반환해야 합니다. macOS는 정상적인 경로 해석 중에 ._<name> 사이드카를 탐색합니다. STALE을 반환하면 마운트가 오염됩니다.

둘 다 docs/ANALYSIS.md에 문서화되어 있습니다.


런타임 값에 대한 참고

RACE 출력의 out 값은 서로 다른 nfsnode에 걸쳐 일정한 하위 48비트 패턴(...7e0023297878)을 가지며, 상위 16비트에서만 달라집니다. 이는 해당 필드가 원시 커널 포인터가 아니라 PAC 서명되었거나 난독화되었음을 확인시켜 줍니다. 사용자 영역에서 상태 전이(NULL → 채워짐)를 관찰할 수는 있지만, 커널의 부팅별 PAC 키 없이는 포인터를 디코딩하거나 역참조할 수 없습니다.

같은 이유로 KDK에 대한 심볼화는 이 값들에 유용하지 않습니다 — 이들은 텍스트 상대 주소가 아닙니다.


크레딧

  • 최초 발견: CVE-2026-43687에 대한 Apple 보안 권고에 따르면 KRsecurity의 R4mbb 및 Peter Malone.
  • 독립적 분석 및 PoC: jvidhan
  • 참조: Apple의 권고와 패치된 바이너리가 취약한 버전과의 비교를 위한 기준으로 사용되었습니다. macOS 26.6 (빌드 25G72)용 KDK가 커널 측 분석을 위한 심볼을 제공했습니다.

면책 조항

이 저장소는 방어적 보안 연구 및 교육 목적으로만 제공됩니다.

  • 소유하고 있거나 테스트에 대한 명시적 서면 허가를 받은 시스템에 대해서만 사용하도록 의도되었습니다.
  • 소유하거나 통제하지 않는 시스템에 이 도구를 사용하는 것은 현지, 국가 또는 국제법을 위반할 수 있습니다.
  • 저자(들)는 이 코드로 인해 발생하는 어떠한 오용이나 손해에 대해서도 어떠한 책임이나 의무도 지지 않습니다.
  • 이 PoC는 커널 경쟁 조건을 입증하는 것으로 제한됩니다. 코드 실행, 권한 상승, 또는 바이트 수준의 메모리 누출을 달성하지 않습니다. 이 PoC로부터의 RCE 또는 전체 메모리 노출에 대한 어떠한 주장도 포함된 분석에 의해 뒷받침되지 않습니다.
  • Apple, macOS, XNU, NFS, autofs, automountd는 Apple Inc.의 상표입니다. 이 프로젝트는 Apple과 제휴하거나 Apple의 승인을 받지 않았습니다.

라이선스

MIT. LICENSE 참조.

도구 다운로드
오프셋macOS 26.6macOS 26.7
+0x158캐시 배열 포인터lck_rw_t
+0x160캐시 카운트(잠금의 일부)
+0x168(기타)캐시 배열 포인터
+0x170(기타)캐시 카운트