[bug] iOS Keychain dump false positive (with source code snippet)
Describe the bug
During an iOS app penetration test, I dumped all keychain entries of the app and noticed "accessible_attribute": "kSecAttrAccessibleAlways", which is deprecated and should be considered a vulnerability for sensitive information in the keychain. After feedback from the developers I've been given the code-snippet where the entry is generated/stored and they undoubtedly configure kSecAttrAccessibleWhenUnlockedThisDeviceOnly for the entry.
I assume this frida/objection reports the wrong accessibility attribute.
To Reproduce Due to an NDA I can not share the application. The relevant source code (redacted/slightly modified):
private func genSav() throws -> SecKey {
var error: Unmanaged<CFError>?
guard let accCtrl = SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
[],
&error
)
var attribs: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag,
kSecAttrAccessControl as String: accCtrl
]
]
guard let genKey = SecKeyCreateRandomKey(attribs as CFDictionary, &error)
return genKey
}
Expected behavior
I would assume the keychain entry should have been reported as kSecAttrAccessibleWhenUnlockedThisDeviceOnly NOT kSecAttrAccessibleAlways.
Evidence / Logs / Screenshots
objection --debug --gadget "target.app" explore
[debug] Agent path is: /usr/local/lib/python3.9/dist-packages/objection/agent.js
[debug] Injecting agent...
Using USB device `iOS Device`
[debug] Attempting to attach to process: `target.app`
[debug] Unable to find process: `target.app`, attempting spawn
[debug] PID `2825` spawned, attaching...
[debug] Resuming PID `2825`
Agent injected and responds ok!
[...]
target.app on (iPhone: 14.4) [usb] # ios keychain dump
Note: You may be asked to authenticate using the devices passcode or TouchID
Save the output by adding `--json keychain.json` to this command
Dumping the iOS keychain...
Created Accessible ACL Type Account Service Data
------------------------- ---------- --- ------------ ------- ------- ------------------------
2021-datetime +0000 Always kSecClassKey (Key data not displayed)
Environment (please complete the following information):
- Device: iPhone SE
- OS: iOS 14.4
- Frida: 15.1.3
- Objection: 1.11.0
- Host OS: Kali Rolling
Application Unfortunately I can't due to the NDA, see the code-snippet above.
What does a dump with --raw look like?
I'm not sure where this is going wrong to be honest. Printing the raw values of the constants using this snippet, I get
NSLog(@"kSecAttrAccessibleAlwaysThisDeviceOnly: %@", kSecAttrAccessibleAlwaysThisDeviceOnly);
NSLog(@"kSecAttrAccessibleAlways : %@", kSecAttrAccessibleAlways);
2021-10-07 11:22:24.771696+0200 PewPew[38505:4210962] kSecAttrAccessibleAlwaysThisDeviceOnly: dku
2021-10-07 11:22:24.771820+0200 PewPew[38505:4210962] kSecAttrAccessibleAlways : dk
That matches what we have for kSecAttrAccessibleAlwaysThisDeviceOnly and kSecAttrAccessibleAlways.
I assume with --raw you mean dump_raw?
Sorry for all the redacting, I'm not sure which of the reported values are confidential, but I recon the interesting attribute here is accc = "<SecAccessControlRef.
Note: You may be asked to authenticate using the devices passcode or TouchID
Dumping the iOS keychain...
{
UUID = "<UUID>";
accc = "<SecAccessControlRef: aku;dacl(true)>";
agrp = "<SOME-ID>.target.app";
atag = {length = 62, bytes = <HEX-VALUES> };
bsiz = 256;
cdat = "2021-datetime";
class = keys;
crtr = 0;
decr = 0;
drve = 1;
edat = "2001-datetime";
encr = 0;
esiz = 0;
extr = 0;
kcls = 1;
klbl = {length = 20, bytes = <HEX-VALUE>};
mdat = "2021-datetime";
modi = 0;
musr = {length = 0, bytes = 0x};
next = 1;
pdmn = dk;
perm = 1;
persistref = {length = 0, bytes = 0x};
priv = 1;
sdat = "2001-datetime";
sha1 = {length = 20, bytes = <HEX-VALUE>};
sign = 1;
sync = 0;
tkid = "com.apple.setoken";
tomb = 0;
type = 73;
"v_Ref" = "<SecKeyRef:('com.apple.setoken') <HEX-VALUE>>";
vrfy = 0;
wrap = 0;
}
I'm definitely no iOS developer, but the code the developers provided seems sound and I've even tested multiple builds of the same application to make sure. I've also ran frida/objection on different hosts with the same result.
This is useful thanks. Look like decodeAcl() has a parsing issue here.
Thank you very much for your hard work, let me know if I can provide further insight or should test anything else.