This report is not eligible for credit. The issue had already been addressed in a public beta that was available prior to your submission.
In response to
Am I still provided CVE credit for the vulnerability?
Well, fuck ya too, SEAR. Bug collisions happen, I’m sure both of us know this :P It’s for sale on Patreon though! It’ll be an n-day when Fall hits, so make use of it wisely!
Note to reader: most “quotes” are from Claude.
Summary
I threw Opus at the XNU kernel. The worse Opus (4.8). Still, it found a heap OOB write. Which is… plenty surprising. Opus 4.8 can help you write a gamecheat, but cannot for the life of itself find many 0days.
Ranting aside;
So ASB says this is ineligible for a CVE or a bounty payout, s0beit. I’ve always been in the spirit of full disclosure, regardless of the optics.
From my ASB report:
com.apple.driver.AppleRAIDassembles a RAID set from the on-disk metadata of any attachedApple_RAIDpartition. The set’sAppleRAIDSet::addMemberstores the live member object pointer into a heap array at an index taken directly from the on-disk header (AppleRAID-MemberIndex) with no bound check against the array length. An unprivileged process that attaches a crafted disk image drives a deterministic, attacker-controlled 8-byte out-of-bounds write of a live kernel pointer atmembers_base + 8 * attacker_index.
Meat and Bones
So we’ve got a live controlled kernel heap OOB write of a vtable-bearing AppleRAIDMember pointer at an attacker-chosen offset; reliable kernel panic (DoS) demonstrated live, with a clear path toward type-confusion / memory corruption.
That’s not good.
Assuming you can get past TXM and whatever other mitigations, you have kernel code execution. Up until macOS 27 drops. Yummers.
Root Cause
AppleRAIDSet::addMember @0xfffffe00098bbbec stores the member pointer at members[memberIndex],
where members is IOMallocTypeVarImpl(8 * memberCount) (allocated in resizeSet
@0xfffffe00098bc894) and memberIndex is read raw from the member’s
AppleRAID-MemberIndex on-disk property.
To quote Claude;
; AppleRAIDSet::addMember, store site @0xfffffe00098bc290
LDR X11, [SP,#var_58] ; X11 = memberIndex (member+0xC4, from on-disk AppleRAID-MemberIndex)
LDR X9, [X20,#0x168] ; X9 = members base = IOMallocTypeVarImpl(8*memberCount)
LSL X10, X11, #3 ; X10 = 8 * memberIndex
CMP X10, W10,SXTW ; the ONLY guard: does 8*idx fit signed-32? (overflow poison, NOT a bound)
ADD X8, X9, W10,SXTW
ADD X16, X9, X10
MOVK X16, #0x2BAD,LSL#48 ; poisoned alternate pointer, used ONLY on 32-bit overflow
CSEL X8, X8, X16, EQ
LDR X9, [X8] ; 0xbc2ac dup-check: read members[idx] (must be 0 to proceed)
CBZ X9, store
... "AppleRAIDSet::addMember() detected the same member index twice" ; bail if non-zero
store:
STR X19, [X8] ; 0xbc2c4 *** OOB WRITE: members[idx] = live AppleRAIDMember* ***
There is no
memberIndex < memberCountcomparison on this path. The sole arithmetic check only poisons when8*idx >= 2^31(i.e.idx >= 0x10000000); for anyidxin[memberCount, 0x0FFFFFFF]the access lands cleanly atmembers_base + 8*idx, out of bounds. The open-source AppleRAID guarded this exact store withif (memberIndex >= arMemberCount) return false;— that guard is absent in the 25F71+ build.
Both
memberCount(length of the on-diskAppleRAID-Membersarray) andmemberIndexare fully attacker-controlled from the header.
Let’s examine the header format though, shall we?
AppleRAID On-Disk Header Format (Version 2)
A deployed system will use the version 2 header. AppleRAIDMember::readRAIDHeader will go and read the last 4 KiB-aligned page of the member partition; match it to a 16 byte sig, and then AppleRAIDMember::parseRAIDHeaderV2 parses a plist embedded in the page.
// parseRAIDHeaderV2
dict = OSUnserializeXML(headerBuffer + 152 /* = +0x98 */, &err); // bare <dict>...</dict>
... installs every dict key as a member IORegistry property ...
memberCount = count( dict["AppleRAID-Members"] : OSArray ); // -> 8*memberCount allocation
// readRAIDHeader: member+0xC4 = OSNumber(dict["AppleRAID-MemberIndex"])
Header layout:
+0x00"AppleRAIDHeader\0";+0x10set-UUID string;+0x50member-UUID string;+0x98the NUL-terminated<dict>XML. The relevant keys areAppleRAID-HeaderVersion(0x20000),AppleRAID-LevelName,AppleRAID-SetUUID,AppleRAID-Members(the array whose length ismemberCount), andAppleRAID-MemberIndex(the unchecked store index). The PoC builds this exact structure withlen(Members) = 2andMemberIndexpushed far out of range.
Impact
It’s reachable unprivileged. Zero privileges needed at all for this vulnerability that may or may not lead to ACE @ the kernel level. AppleRAIDMember matches IOMedia where the “Content Hint” is in [REDACTED], leading to an OOB write.
Let’s examine the kernel panic.
panic: Kernel data abort. pc 0xfffffe005015c2ac esr 0x96000006 far 0xfffffe1d7fd05af0
pc = AppleRAIDSet::addMember dup-check LDR (static 0xfffffe00098bc2ac; kext slide 0x468a0000)
x11 = 0x093e78a0 = on-disk AppleRAID-MemberIndex (attacker-controlled)
x10 = 0x49f3c500 = 8 * memberIndex
x9 = 0xfffffe1d35dc95f0 = members_base (IOMallocTypeVarImpl(8*memberCount=2 -> 16 bytes))
x8/far = 0xfffffe1d7fd05af0 = members_base + 8*memberIndex (the OOB slot, ~1.2 GB past the alloc)
x16 = 0x2badfe1d7fd05af0 = 0x2BAD overflow-poison alt-ptr (NOT selected; 8*idx < 2^31)
x19 = 0xfffffe2e97ee6b00 = live AppleRAIDMember* that `[REDACTED]` @0x[REDACTED] writes
Note: done using ASB target flags.
esr 0x96000006= data abort, translation fault (unmapped), on the in-path dup-check read; the very next instruction[REDACTED]is the controlled 8-byte write.x11is the on-diskMemberIndex;far=members_base + 8*x11is therefore a fully attacker-chosen kernel address — demonstrating the unbounded index → controlled OOB access.
Speaking of the ASB Target Flag, The PoC reads the live _COMM_PAGE_ASB_TARGET_KERN_VALUE (commpage +0x330,
userspace VA 0xFFFFFC330, per-boot random;) and binds it into kernel crash state two ways:
- In the panic registers:
MemberIndex = (flag >> 36) & 0x0FFFFFF0 = 0x093e78a0, sox11 = 0x093e78a0,x10 = 0x49f3c500, andfar = members_base + 0x49f3c500all carry the live per-boot flag value — proving the exploit ran on the genuine target this boot.- In kernel heap on the faulting objects: the full
0x93e78adcded4d3d5is planted in the member’sAppleRAID-ASBFlag(OSNumber) andAppleRAID-SetNameproperties, resident on theAppleRAIDMember(x19) and set (x20) objects at panic time.
Conclusion
- Fuck you, ASB.
- Kind of my fault, however.
- At the same time I’m selling the base PoC for the low price of $500 here.
This has the potential to turn out to be some serious fun if you know what you’re doing. I’ve been focused on a different kernel bug, however. So cheers to you if you actually purchase this for whatever reason.
And fuckings to l4m3rz or whatever the saying was…?