
CVE-2025-31200 - @Noahhw46 figured it out
CoreAudio 패치(CVE-2025-31200)에 대한 개념 증명, iOS 18.4.1에서. 설명 글은 https://blog.noahhw.dev/posts/cve-2025-31200/ 에 있습니다.
이를 제한된 범위이지만 임의 쓰기로까지 발전시킬 수 있었습니다. 설명 글은 곧 올라옵니다. 직접 확인하려면 패치 이전 버전의 macOS(< 15.4.1)에서 빌드해야 합니다. check-mismatch lldb 훅을 사용하여(간단한 harness로 오디오를 재생하는 방식) 오디오를 재생하면 쓰기를 확인할 수 있습니다. 아직 완전한 임의 쓰기는 아닙니다. 위에서 언급했듯이 몇 가지 이유가 있지만, 주로 프레임 버퍼의 값들이 리매핑될 때 디코딩 파이프라인의 어느 단계에 있는지 아직 100% 확신하지 못하기 때문입니다. 누군가 이어서 작업할 의향이 있다면, 저는 여기서 멈추고 설명 글을 작성하겠습니다.
저(@noahhw46)와 @zhouwei의 설정 덕분에 알아냈습니다(설명 글 곧 올라옵니다). 하지만 여전히 이해해야 할 부분이 많습니다. 이 버그가 실제로 무엇을 하는지 정확히 보여주기 위해 조사의 다음 단계 첫 번째 부분을 여기에 추가했습니다. check-mismatch는 또 다른 lldb 스크립트로, 작동하는 poc와 함께 사용하여 APACChannelRemapper::Process(실제로는 APACHOADecoder::DecodeAPACFrame 내부)에서 mRemappingArray와 permutation map 사이에 생성된 불일치를 정확히 보여줍니다.
mRemappingArray의 크기는 mChannelLayoutTag의 하위 2바이트를 기준으로 결정됩니다.
이들 사이에 불일치를 만들면 APACHOADecoder::DecodeAPACFrame의 이후 처리 단계가 손상됩니다.
APACHOADecoder가 APAC 프레임을 처리할 때(채널 리매핑 배열에 따라 프레임을 순열 변환), mRemappingArray를 permutation map으로 사용하여 채널 리매핑을 수행합니다. 리매핑되는 프레임 데이터의 크기는 mTotalComponenets에 기반하는 것으로 보입니다.
output.mp4 오디오 파일을 재생하면(예: AVAudioPlayer 사용), APACChannelRemapper::Process가 경계를 벗어난 읽기와 쓰기를 수행합니다.
Xcode에서 Guard Malloc을 활성화하면 첫 번째 경계를 벗어난 읽기를 확인할 수 있습니다:
Guard Malloc 없이 실행하면, APACHOADecoder::DecodeAPACFrame이 나중에 잘못된 memmove로 크래시를 일으킵니다:
@zhuowei의 이전 README는 아래와 같습니다:
CoreAudio 패치(CVE-2025-31200)를 iOS 18.4.1에서 이해하려고 시도 중입니다.
아직 알아내지 못했습니다.
현재 macOS 15.4.1에서 output.mp4를 디코딩할 때 다른 오류 메시지가 나타납니다:
error 01:10:26.743480-0400 getaudiolength <private>:548 Invalid mRemappingArray bitstream in hoa::CodecConfig::Deserialize()
error 01:10:26.743499-0400 getaudiolength <private>:860 Error in deserializing ASC components
vs visionOS 2.2용 Xcode 시뮬레이터:
error 01:09:21.841805-0400 VisionOSEvaluation APACProfile.cpp:424 ERROR: Wrong profile index in GlobalConfig
error 01:09:21.841914-0400 VisionOSEvaluation APACGlobalConfig.cpp:894 Profile and level data could not be validated
그래서 새로운 검사에 걸리지만, 실제로 무언가를 덮어쓰게 만드는 방법을 모르겠습니다.
변경된 함수는 apac::hoa::CodecConfig::Deserialize로, /System/Library/Frameworks/AudioToolbox.framework/AudioCodecs에 있는 것으로 보입니다.
APAC는 Apple Positional Audio Codec입니다.
HOA는 Higher-order Ambisonics입니다.
ffmpeg 이슈 트래커의 샘플 파일을 살펴보면:
$ avmediainfo ~/Downloads/clap.MOV
Asset: /Users/zhuowei/Downloads/clap.MOV
<...>
Track 3: Sound 'soun'
Enabled: No
Format Description 1:
Format: APAC 'apac'
Channel Layout: High-Order Ambisonics, ACN/SN3D
Sample rate: 48000.0
Bytes per packet: 0
Frames per packet: 1024
Bytes per frame: 0
Channels per frame: 4
Bits per channel: 0
System support for decoding this track: Yes
Data size: 43577 bytes
Media time scale: 48000
Duration: 0.898 seconds
Estimated data rate: 363.142 kbit/s
Extended language tag: und
1 segment present
Index Media Start Media Duration Track Start Track Duration
1 00:00:00.000 00:00:00.898 00:00:00.000 00:00:00.898
Member of alternate group 0: (2, 3)
afconvert -o sound440.m4a -d apac -f mp4f sound440hz.wav로 APAC으로 변환할 수 있습니다.
iOS 18.4.1과 18.4를 bindiff로 비교해보면, mRemappingArray를 읽을 때 이제 오프셋 0x78에 있는 리매핑 AudioChannelLayout* 대신 오프셋 0x58에 있는 전역 AudioChannelLayout*의 채널 수를 확인하는 것으로 보입니다.
encodeme.mm 파일은 APAC을 인코딩하며, LLDB 스크립트는 mRemappingArray와 리매핑 AudioChannelLayout에 추가 요소를 강제로 넣습니다:
./build_encodeme.sh
./run_encodeme.sh