MAC上导出Non-extractble的证书和私钥

0x00 背景

如果MAC上的私钥被倒入时使用了-x选项,择该私钥在导入后无法从Keychain中导出。这个选项常用于公司管理下的电脑,不想让员工导出安装好的私钥。但是实际上这个私钥还是在员工的电脑里,所以一定有办法提取这个私钥。

0x01 提取

受这个回答启发:
https://stackoverflow.com/questions/25109994/non-extractable-private-key-in-keychain-on-os-x/25213646#25213646

查看这个回答给的链接,然后经过debug实验,我发现导出p12证书和私钥的函数为p12WrapKey
https://opensource.apple.com/source/Security/Security-55471.14/libsecurity_pkcs12/lib/pkcs12Crypto.cpp

所以导出步骤为:
1. 打开Keychain App
2. ps aux | grep Keychain
3. lldb -p {pid of Keychain}
4. b p12WrapKey
5. disassemble --start-address 0x7fff4b58c12b --count 40,这里0x7fff4b58c12bp12WrapKey的起始地址。然后我们找到第一个分支语句,大概长这样:

0x7fff4b58c178 <+77>:  testb  $0x20, 0x28(%rsi)
0x7fff4b58c17c <+81>:  je     0x7fff4b58c39f            ; <+628>

这句话对应着源代码的if语句:

/* key must be extractable */
if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
    return errSecDataNotAvailable;
}

所以把这个testb语句之后的je语句给nop掉就好了。
6. memory write 0x7fff4b58c17c 0x90 0x90 0x90 0x90 0x90 0x90,0x7fff4b58c17c为je语句的地址,这个je语句占用6个字节,所以我们连续nop掉6个字节。
7. 在lldb中continue,然后操作你的Keychain App进行导出即可。