Skip to content

Instantly share code, notes, and snippets.

@kfriend
Last active July 10, 2016 14:24
Show Gist options
  • Save kfriend/5272308 to your computer and use it in GitHub Desktop.
Save kfriend/5272308 to your computer and use it in GitHub Desktop.
OS X Keychain dumping script written in PHP. Dumps keychains to JSON.
#!/usr/bin/php
<?php
/**
* OS X Keychain Dump to JSON
*
* Big thanks to Romeo for outlining the initial steps for this:
* http://romeotheriault.blogspot.com/2009/01/exporting-mac-os-x-keychain-access.html
*
* Notes:
* - Dump files will be stored in the cwd.
* - You'll need to hit "Allow" for every entry in a keychain during the dumping stage.
* - This script will dump only the current user's keychains.
* - This script has only been tested with OS X 10.7 (Lion) and PHP 5.3 and 5.4.
*
* Future to do:
* - Somehow work in Applescript to click "Allow" during the keychain dumping phase.
*
* @author Kevin Wood-Friend
*/
// Backward compatibility for PHP < 5.4
if (!defined('JSON_PRETTY_PRINT')) define('JSON_PRETTY_PRINT', 0);
// Get user's keychains
$keychains = explode("\n", `security list-keychains | grep \`whoami\``);
// Clean up entries
$keychains = array_map(function($keychain) {
return trim(trim($keychain), '"');
}, $keychains);
// Filter out empty values
$keychains = array_filter($keychains);
foreach ($keychains as $keychain)
{
$keychainName = pathinfo($keychain, PATHINFO_BASENAME);
$keychainPassword = prompt_silent("Enter password for {$keychainName}. Leave blank to skip: ");
if ($keychainPassword === '')
{
puts("Skipping {$keychainName}");
continue;
}
puts('Unlocking '.$keychainName);
// If incorrect password used, OS X will prompt for password
`security unlock-keychain -p {$keychainPassword} $keychain`;
unset($keychainPassword);
$saveTo = getcwd().'/'.pathinfo($keychainName, PATHINFO_FILENAME).'.json';
puts("Dumping {$keychainName} to {$saveTo}");
$export = `security dump-keychain -d {$keychain}`;
$parts = explode('keychain:', $export);
$passwords = array();
foreach ($parts as $key => $part)
{
if ($part === '') continue;
preg_match('/0x00000007 <blob>="(.*)"/', $part, $name);
preg_match('/"acct"<blob>="(.*)"/', $part, $username);
preg_match('/data:\s*"(.*)"/', $part, $password);
preg_match('/"svce"<blob>="(.*)"/', $part, $address);
$passwords[] = array(
'name' => isset($name[1]) ? $name[1] : null,
'username' => isset($username[1]) ? $username[1] : null,
'password' => isset($password[1]) ? $password[1] : null,
'location' => isset($address[1]) ? $address[1] : null,
);
}
file_put_contents($saveTo, json_encode($passwords, JSON_PRETTY_PRINT));
}
/**
* Prompt silent
*
* Interactively prompts for input without echoing to the terminal.
* Requires a bash shell or Windows and won't work with
* safe_mode settings (Uses `shell_exec`)
*
* Source: http://www.sitepoint.com/interactive-cli-password-prompt-in-php/
* Edits: Stripped unneeded Windows check
*/
function prompt_silent($prompt = "Enter Password:")
{
$command = "/usr/bin/env bash -c 'echo OK'";
if (rtrim(shell_exec($command)) !== 'OK') {
trigger_error("Can't invoke bash");
return;
}
$command = "/usr/bin/env bash -c 'read -s -p \""
. addslashes($prompt)
. "\" mypassword && echo \$mypassword'";
$password = rtrim(shell_exec($command));
echo "\n";
return $password;
}
function puts($string)
{
echo $string.PHP_EOL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment