Once upon a time, we could run a command like the following to dump all our keychain data:
security dump-keychain -d ~/Library/login.keychain > ~/Desktop/dump.txt
I go into more detail on those techniques in an article I did back in 2009, here:
Now there are more keychains and the entitlements for the security binary to access this kind of information has changed. We can make some changes to the authorizationdb (as explored in https://krypted.com/utilities/authorizationdb-defaults-macos-10-14/) but I’ve yet to find a magic combination that allows me to script interactions with the keychain without a GUI pop-up (and one that blocks synthetic interaction.
The data for each keychain is stored in an encrypted sqlite database. There’s the System Keychain at /Library/Keychains and then there’s our login.keychain at ~/Library/Keychains. The above command simply dumps nothing to that txt file. Yet we can still programmatically get to the passwords, just with a little laborious process as we grant access to objects to the security binary. The keychain we want to interrogate is actually ~/Library/login.keychain-db in most cases so we can run the following to dump the contents to the screen:
security dump-keychain -d ~/Library/login.keychain-db
Every time the security command attempts to interact with an object in a new domain we will have to enter the password and click Allow or Always Allow. Always Allow doesn’t work for all objects.
We can then see raw password values in <Data> keys here and there as well as the service (or svce for short) of the object. It’s hard to imaging anyone wanting to enter the password for each item in the keychain, especially given how rarely the keychains are there for. Having said this, there is some interesting cruft in that directory. For example, it’s not uncommon to see a login_renamed_1.keychain-db that dates back years, or login.keychain-db.OLD.keychain-db. That’s because certain operations either make a copy or move a file out of the way so the login keychain can be unlocked, even if it’s a net-new keychain. There’s also a keychain in there for metadata and some vendors have written their own keychains, primarily to store keys.
This same paradigm is true with the generic password options through security, so for each we’ll need the name or a quoted full site (which we’ll call $nameofservice below):
security find-generic-password -gs $nameofservice
The once exception is that if the security command creates the object, it should be able to read it (here we variabalize the username and password as $user and $password respectively):
security add-generic-password -a $user -s $nameofservice -w $password -T ""
This too results in the password dialog screen. In general, we can still do all the things we’ve always been able to do with security – it might just be a bit more labor intensive. One thing that’s changed drastically is that a lot of objects just include pointers. We might see a token for many sites, as seen below:
This indicates that a full secret is available in plaintext and is common for example, for sites that persist logins across multiple reboots that span months (at least until a token and/or cookie are revoked). However, with the addition of the T2 we might instead see an elliptical curve key that must be paired with one stored in the Secure Enclave in order to produce a secret in clear text. Given that modern binaries are secure runtimes those are a bit more challenging to get at.