{
	"id": "4b540e01-33c7-4c1b-a2a1-45575d225635",
	"created_at": "2026-04-06T01:31:24.393671Z",
	"updated_at": "2026-04-10T03:24:29.495697Z",
	"deleted_at": null,
	"sha1_hash": "0f4bda91c0c1440a6feb232b2f2e767b73f83b7b",
	"title": "Breaking into the OS X keychain",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 147995,
	"plain_text": "Breaking into the OS X keychain\r\nArchived: 2026-04-06 01:26:51 UTC\r\nThe Wayback Machine -\r\nhttps://web.archive.org/web/20130106164109/http://juusosalonen.com:80/post/30923743427/breaking-into-the-os-x-keychain\r\nUpdate: I want to clear up some misconceptions. This is not a security bug in OS X. Everything works as\r\ndesigned. The point of this post was to show a post-exploitation technique and to release a tool for the job. I found\r\nthis particular technique interesting because it is instantaneous, reliable across OS X versions, and requires no\r\npersistent changes in the system.\r\nTL;DR: Root can read plaintext keychain passwords of logged-in users in OS X. Open source proof-of-concept.\r\nThere is a design compromise in Apple’s keychain implementation that sacrifices some security for a lot of\r\nusability.\r\nAs a result, the root user is able to read all keychain secrets of logged-in users, unless they take extra steps to\r\nprotect themselves. I’m sure Apple is perfectly aware of the security implications, and made the bargain\r\nintentionally.\r\nBecause this is an intentional design decision instead of a security bug, its exploitation should not come as a\r\nsurprise. However, I haven’t seen anyone actually use or mention any practical methods before in public.\r\nThe situation\r\nIn OS X, your keychain contains your saved passwords. This includes all your email accounts in Mail, passwords\r\nstored in Safari, and credentials for accessing known Wi-Fi networks. Because it contains valuable secrets, the\r\nkeychain is encrypted. It can only be opened with your login password.\r\nBut there’s a twist. When you log in to OS X, the operating system automatically unlocks your keychain for your\r\nconvenience. This means that you don’t have to enter your login password every time you want to use your stored\r\npasswords.\r\nThat’s why, by default, you see keychain dialogs like this\r\nhttps://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain\r\nPage 1 of 4\n\ninstead of this\r\nNotice that only one of them asks for your password. Most users are probably much happier with the no-password-needed dialog, so that’s what Apple implemented. Of course, this means that it has to be somehow\r\npossible to read your keychain passwords even without asking for your login password every time. That’s what\r\n“unlocking” means here.\r\nSo, your passwords are encrypted to keep them safe, but they have to be readable by OS X itself to keep you\r\nhappy. That’s a bit of a dilemma. Apple’s solution is threefold.\r\nUnlocking does not change the keychain file. The plaintext passwords do not appear on disk (or in\r\nmemory), even when they are unlocked.\r\nApple provides an official API for reading unlocked passwords. Even though it does allow you to read\r\nthem, it also asks for the user’s permission with a dialog window.\r\nhttps://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain\r\nPage 2 of 4\n\nWhat unlocking actually does or how the unlocked passwords are accessed is not documented. This is\r\nsecurity through lack-of-documentation.\r\nThe attack\r\nThe passwords in a keychain file are encrypted many times over with various different keys. Some of these keys\r\nare encrypted using other keys stored in the same file, in a russian-doll fashion. The key that can open the\r\noutermost doll and kickstart the whole decryption cascade is derived from the user’s login password using\r\nPBKDF2. I’ll call this key the master key.\r\nIf anyone wants to read the contents of a keychain file, they have to know either the user’s login password or the\r\nmaster key. This means that securityd , the process that handles keychain operations in OS X, has to know at\r\nleast one of these secrets.\r\nI put this observation to the test on my own laptop.\r\nScanning securityd ’s whole memory space did not reveal any copies of my login password. Next, I used\r\nPBKDF2 with my login password to get my 24-byte master key. Scanning the memory again, a perfect copy of the\r\nmaster key was found in securityd ’s heap.\r\nThis lead to the next question. If the master keys are indeed stored in securityd ’s memory, is there a good way\r\nto find them? Testing every possible 24-byte sequence of the memory space is not very elegant.\r\nInstead of fully inspecting securityd ’s whole memory space, possible master keys can be pinpointed with a\r\ncouple of identifying features. They are stored in securityd ’s heap in an area flagged as MALLOC_TINY by\r\nvmmap . In the same area of memory, there’s also always structure pointing to the master key. The structure\r\ncontains an 8-byte size field with the value of 0x18 (24 in hex) and a pointer to the actual data.\r\nThe search is rather simple:\r\nFind securityd ’s MALLOC_TINY heap areas with vmmap\r\nSearch each found area for occurrences of 0x0000000000000018\r\nIf the next 8-byte value is a pointer to the current heap area, treat the pointed-to data as a possible master\r\nkey\r\nWith this kind of pattern recognition, the number of possible master keys is reduced to about 20. Each of the\r\ncandidates can be used to try to decrypt the next key (which I call the wrapping key). Only the real master key\r\nshould spit out a sensible value for the wrapping key. It’s not a foolproof method, but with the low number of\r\ncandidates it seems to be good enough. I haven’t run into a single false positive yet.\r\nThe rest of the decryption process is rather tedious. The master key reveals the wrapping key. A hardcoded\r\nobfuscation key reveals the encrypted credential key. The wrapping key reveals the credential key. The credential\r\nkey finally reveals the plaintext password. All glory to Matt Johnston for his research on these decryption steps.\r\nHere is a sample run and its truncated output, with actual passwords and usernames replaced with x’s.\r\nhttps://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain\r\nPage 3 of 4\n\n$ sudo ./keychaindump\r\n[*] Searching process 15 heap range 0x7fa809400000-0x7fa809500000\r\n[*] Searching process 15 heap range 0x7fa809500000-0x7fa809600000\r\n[*] Searching process 15 heap range 0x7fa809600000-0x7fa809700000\r\n[*] Searching process 15 heap range 0x7fa80a900000-0x7fa80ac00000\r\n[*] Found 17 master key candidates\r\n[*] Trying to decrypt wrapping key in /Users/juusosalonen/Library/Keychains/login.keychain\r\n[*] Trying master key candidate: b49ad51a672bd4be55a4eb4efdb90b242a5f262ba80a95df\r\n[*] Trying master key candidate: 22b8aa80fa0700605f53994940fcfe9acc44eb1f4587f1ac\r\n[*] Trying master key candidate: 1d7aa80fa0700f002005043210074b877579996d09b70000\r\n[*] Trying master key candidate: a0a20000000200f7474d400000700d01a980fa00007f085e\r\n[*] Trying master key candidate: 180000000000000000000000000000000000000007000001\r\n[*] Trying master key candidate: 0000b107000001000000803e970aa8710ae567eff7ff0000\r\n[*] Trying master key candidate: 796a63507e6c2a84d9f095fae2896058dfe029cd0f7105da\r\n[*] Trying master key candidate: 16ac866d636215c01e337e942f48cfed12d7c45bfab8dbf7\r\n[*] Trying master key candidate: 070020539baab0d1d6a3aa80fa006877ed57f80fa0000000\r\n[*] Trying master key candidate: 88edbaf22819a8eeb8e9b75120c0775de8a4d7da842d4a4a\r\n[+] Found master key: 88edbaf22819a8eeb8e9b75120c0775de8a4d7da842d4a4a\r\n[+] Found wrapping key: e9acc39947f1996df940fceb1f458ac74b877579f54409b7\r\nxxxxxxx:192.168.1.1:xxxxxxx\r\nxxxxxxx:news.ycombinator.com:xxxxxxx\r\nxxxxxxx@gmail.com:login.facebook.com:xxxxxxx\r\nxxxxxxx@gmail.com:smtp.google.com:xxxxxxx\r\nxxxxxxx@gmail.com:imap.google.com:xxxxxxx\r\nxxxxxxx@gmail.com:api.heroku.com:xxxxxxx\r\nxxxxxxx:www.freechess.org:xxxxxxx\r\nxxxxxxx:twitter.com:xxxxxxx\r\nxxxxxxx@gmail.com:www.google.com:xxxxxxx\r\nxxxxxxx:imap.gmail.com:xxxxxxx\r\n...\r\nYou can find the source code for keychaindump at GitHub. It’s a proof-of-concept, far from perfect, and it doesn’t\r\nlist all the possible keychain secrets. But it seems to work okay. I’ve tested it on OS X Lion and Mountain Lion.\r\nSource: https://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain\r\nhttps://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://web.archive.org/web/20130106164109/https://juusosalonen.com/post/30923743427/breaking-into-the-os-x-keychain"
	],
	"report_names": [
		"breaking-into-the-os-x-keychain"
	],
	"threat_actors": [
		{
			"id": "aa73cd6a-868c-4ae4-a5b2-7cb2c5ad1e9d",
			"created_at": "2022-10-25T16:07:24.139848Z",
			"updated_at": "2026-04-10T02:00:04.878798Z",
			"deleted_at": null,
			"main_name": "Safe",
			"aliases": [],
			"source_name": "ETDA:Safe",
			"tools": [
				"DebugView",
				"LZ77",
				"OpenDoc",
				"SafeDisk",
				"TypeConfig",
				"UPXShell",
				"UsbDoc",
				"UsbExe"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775439084,
	"ts_updated_at": 1775791469,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/0f4bda91c0c1440a6feb232b2f2e767b73f83b7b.pdf",
		"text": "https://archive.orkl.eu/0f4bda91c0c1440a6feb232b2f2e767b73f83b7b.txt",
		"img": "https://archive.orkl.eu/0f4bda91c0c1440a6feb232b2f2e767b73f83b7b.jpg"
	}
}