Component: AppleKeyStore kernel extension — _LibSer_SEPControl_Deserialize
Affected: iOS / iPadOS 26.6 (23G71) and earlier
Fixed in: iOS / iPadOS 26.6.1 (23G83)
Type: Out-of-Bounds read in SEP control message deserialization
Impact: Kernel pointer leak → KASLR defeat; triggerable from any process with direct AKS IOKit access (root / jailbreak / post-sandbox-escape)
Root Cause
_LibSer_SEPControl_Deserialize in the AppleKeyStore kernel extension publishes a (payload_ptr, declared_length) pair from an ACM (Credential Manager) message buffer to userspace via copyout(), without validating that declared_length ≤ remaining.
By supplying declared_length = 0x800, the driver copies approximately 0x7E8 bytes beyond the end of the kernel ACM message buffer — reading into adjacent kernel heap allocations. Those adjacent regions contain kernel pointers (0xfffffff0xxxxxxxx) which can be used to compute the KASLR slide.
; _LibSer_SEPControl_Deserialize (affected path, 26.6 / 23G71)
ldr w2, [acm_msg + declared_length_offset] ; user-controlled 0x800
; NO check: w2 <= (acm_msg_end - payload_ptr) ← MISSING
bl copyout ; copies w2 bytes to userspace
ACM Handle Capture
Direct IOServiceOpen("AppleKeyStore") is blocked by the sandbox on sideloaded apps.
The PoC includes a DYLD_INTERPOSE hook on IOConnectCallMethod that attempts to capture a real ACM session handle from an in-process SE key-signing call — working in environments where Security.framework makes the IOKit call directly (non-sandboxed / debug / older iOS configurations).
Physical device note (iOS 26, tested on iPhone 12 / 23G71): On current iOS 26 builds, Security.framework routes all Secure Enclave operations through ctkd (CryptoTokenKit daemon) via XPC. The IOConnectCallMethod call to AKS happens inside ctkd, never in the calling process. The DYLD_INTERPOSE hook therefore does not fire, and direct IOServiceOpen is sandbox-blocked. Triggering the OOB on a physical device requires breaking out of the sandbox first (e.g. via a UAF in IOGPUFamily → kernel task port → open AKS directly).
Chain:
- Arm the interpose capture flag
SecKeyCreateRandomKey(kSecAttrTokenIDSecureEnclave)→SecKeyCreateSignature()→ capture in-processIOConnectCallMethodif available- Capture
(conn, handle[16])— or open AKS directly if sandbox is bypassed - Replay with
declared_length = 0x800across 163 AKS selectors - Scan output for
0xfffffff0xxxxxxxxkernel pointers → compute KASLR slide
PoC Behaviour
poc_aks_oob.m implements the full ACM handle capture and OOB probe chain:
- Creates a Secure Enclave P-256 key (
kSecAttrAccessibleAfterFirstUnlock, no biometric) - Signs a 32-byte message to trigger the in-process AKS IOKit call
- Replays with
declared_length = 0x800across all 163 AKS selectors - Prints any kernel pointers found at
KPTR @+XXXX = 0xfffffff0YYYYYYYY - Attempts to compute the KASLR slide from a known AKS symbol offset
If the SE key sign is routed through secd XPC instead of in-process, the fallback probe uses a zero handle (confirms OOB path reachability; all selectors will fail ACM validation, but the VNOP path is confirmed).
iOS 26 Note: fishhook Blocked
On iOS 26, __DATA_CONST (which contains the GOT) is mapped read-only before any in-process code runs. Runtime GOT writes (as used by fishhook) trigger KERN_PROTECTION_FAILURE → SIGBUS. DYLD_INTERPOSE via __DATA,__interpose works because dyld processes the interpose table at image-load time, before the kernel enforces the __DATA_CONST protection.
Requirements
- iOS 26.6 (23G71) or earlier
- Secure Enclave access (
kSecAttrTokenIDSecureEnclave) — available to any sideloaded app without entitlements - Sandbox escape required on physical iOS 26 devices: SE key signing routes through
ctkdXPC (not in-process). DirectIOServiceOpen("AppleKeyStore")is sandbox-blocked. The OOB is reachable from root/jailbreak context; as a chain step it follows a sandbox escape (e.g. IOGPUFamily UAF → kernel task port). - In non-sandboxed / debug environments the in-process DYLD_INTERPOSE path works without any escape.
Build
# Xcode project — link Security.framework and Foundation.framework
clang -arch arm64 \
-isysroot $(xcrun --sdk iphoneos --show-sdk-path) \
-framework Security -framework Foundation \
-o poc poc/poc_aks_oob.m
codesign -s "Apple Development" --entitlements ent.plist poc
Minimum entitlements (ent.plist):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>keychain-access-groups</key>
<array><string>$(AppIdentifierPrefix)com.research.poc65343</string></array>
</dict></plist>
Timeline
| Date | Event |
|---|---|
| 2026-08-17 | iOS 26.6.1 released with fix |
| 2026-08-17 | Apple credits published in security advisory |
Comments