Passwords are a modern annoyance and their diversity is something you can’t avoid if you want a minimum amount of account security (don’t forget to turn on those 2FA options, avoiding SMS versions if possible). They get more annoying when you set a super smart new password with that smug feeling that it is such a great password that you will never forget about it (or something crappy you set in a rush). Usually you can’t remember it already in the next day or in the next week, since in a month it is totally wiped out from your memory.
This time my victim was Carbon Copy Cloner (CCC). When you generate a backup you can select an encrypted sparse bundle (disk image) as destination, and save its password in the application private keychain.
Some time ago I created some backups in a hurry and used the encrypted sparse bundle option as destination. Of course I used a super smart password and now I couldn’t remember it. Carbon Copy Cloner was still able to make the backups to that image but I couldn’t open it myself (well it is mounted during a backup but that is not fun enough to write a blogpost about!). I knew CCC had a private keychain somewhere in the system (/Library/Application Support/com.bombich.ccc/CCC-global.keychain
to be precise) so my goal was to click Keychain Access show password radio button to recover the password.
The problem is that the private keychain is locked with a password and I couldn’t find any information about this password. Is it dumb enough to be hardcoded? Or is it something smarter and generated per user/machine/etc? Well the latter is the obvious answer now since this post titles gives it up.
Given that CCC has a privileged helper tool, it is a pretty good assumption that it will be responsible for managing the private keychain (because it runs with higher privileges and protects keychain access from regular users). So load up /Library/PrivilegedHelperTools/com.bombich.ccchelper
into your favorite disassembler. While waiting for disassembly to complete we can try to guess what to look for.
If CCC is using macOS keychain infrastructure then we should be able to see Keychain related APIs in this binary.
$ nm /Library/PrivilegedHelperTools/com.bombich.ccchelper|grep -i keychain
U _SecKeychainCopySearchList
U _SecKeychainCreate
U _SecKeychainFindGenericPassword
U _SecKeychainFindInternetPassword
U _SecKeychainGetStatus
U _SecKeychainItemCopyAttributesAndData
U _SecKeychainItemCreateFromContent
U _SecKeychainItemDelete
U _SecKeychainItemFreeAttributesAndData
U _SecKeychainItemFreeContent
U _SecKeychainItemModifyAttributesAndData
U _SecKeychainLock
U _SecKeychainOpen
U _SecKeychainSetSearchList
U _SecKeychainSetSettings
U _SecKeychainSetUserInteractionAllowed
U _SecKeychainUnlock
SecKeychainUnlock
appears to be a good first candidate to poke around. Apple’s API documentation has everything we need to know about this:
OSStatus SecKeychainUnlock(SecKeychainRef keychain, UInt32 passwordLength, const void *password, Boolean usePassword);
password
A buffer containing the password for the keychain. Pass NULL if the user password is unknown. In this case, this function displays the Unlock Keychain dialog to prompt the user for the keychain password.
A cleartext password is passed to SecKeychainUnlock
to unlock the keychain. Took longer to disassemble than to find what we need to attack! IDA gives us the following cross references and we can see a very suggestive function name (strip the symbols!).
__stubs:100168D76 _SecKeychainUnlock proc near ; CODE XREF: _openAndUnlockCCCKeychain+30C
__stubs:100168D76 ; _openAndUnlockCCCKeychain+626
__stubs:100168D76 jmp cs:_SecKeychainUnlock_ptr
__stubs:100168D76 _SecKeychainUnlock endp
Tip: to strip symbols in Xcode the “Deployment Postprocessing” build option must be set to Yes, otherwise the binary will not be stripped.
If you poke around openAndUnlockCCCKeychain
you will understand that the password is being created at the function kp
. It returns a NSString object. So right now it is very easy to recover the unknown CCC keychain password. Just attach with a debugger to the privileged helper process, and breakpoint on the address after the call to kp
. Print the object in rax
register and voila the password is all there (a long mumbo jumbo of weird characters, impossible to bruteforce). To trigger the breakpoint just quit CCC and open it again (the helper process is still running in the background and the debugger is attached). That’s it, it really takes longer to disassemble than to recover the password. The helper process is not SIP protected so the debugger can be attached without any problems.
To test the password, copy the keychain to somewhere else, change permissions to current user and open the keychain. Insert the password, and voila it unlocks. Go to saved keychain items, click show password and our mission is complete. The password I had set was a really dumb one, and I was trying all the complex stuff I could remember of. Ah the joy of new passwords rush!
Well this wasn’t that much fun, so I got curious about the password generation algorithm. Time to poke around the kp
function. The function isn’t very complicated so I will not lose much time with details. It collects the following information about the machine where it is running:
- IOPlatformUUID
- IOPlatformSerialNumber
- Hardware model name (via CTL_HW/HW_MODEL sysctl)
- Number of CPUs (via sysctl)
This gives a strong hint that the password is specific to each machine where CCC is executed (a positive thing!). With this information some transformations are done and a 64 characters password is generated. The kp
function is called when the password is necessary (just from the openAndUnlockCCCKeychain
function) but remains constant per machine. Given this it is very easy to build a keygen. The source for mine is available here carbon_copy_cloner_keychaingen. The code is pretty much a direct translation from the disassembled code and could be improved/optimized. I opted out to sync it with the disassembly in the comments so you could try to understand what is going on.
After all this I have a problem with this solution…
Creating a private keychain that contains passwords to encrypted backups with a password that is out of my choice and constant per machine is something I don’t really like. This password is very easy to keygen or recover with a debugger. I assume we need to run the keygen in the target machine (can IOPlatformUUID and/or IOPlatformSerialNumber be known without running code?) or a debugger (for which we need admin privileges).
I understand those saved encrypted backups passwords to be at higher risk of disclosure since I don’t control the password that guards them.
Of course there are (valid) reasons for this design - easy usage and automatic backups. It is after all a software product with wide customer audience and not just experts - regular people just want stuff to work (it is already a huge step forward if they bought backup software and actively execute backups).
You can opt out for not saving the password in the keychain. But the incentives to do it are there and most users will follow them without fully understanding the risks involved. The flip side of the coin is that I could have lost my encrypted backups because I didn’t save their password in the keychain. Personally I am biased against macOS keychain, and never save any important passwords there. I view it as some sort of a single point of failure and malware is usually interested on its contents (if you use it, don’t use the login keychain for those secrets, create a new one that is only unlocked when you really need it).
I prefer to lose data than have it accessed by unknown third parties!
Have fun,
fG!