Extracting and cracking MacOSX SHA512 passwords

Long story short, I love my fiance though she may be somewhat lacking in the technical area. She’s got a work-issue laptop with a built-in “Administrator” account that has locked down parts of the machine we want access to. So how to get in?

A nice post on apple stackexchange here helped me understand how the password encryption works on the backend (it’s SHA512), as well as rip out a pretty plist file with the hashed password data and get it ready for cracking. From there I’ll use my favorite cracker hashcat to break the actual password.

I’ve already been able to create a sudo-able account on this machine (this I finagled some time back when one of the “tech support guys” was helping us out and he made a little mistake). Outside of the scope of this article, but if you don’t have a sudo locally you might be able to boot into single-user mode which will give you root by powering off your machine and holding down command+s as it boots back up.

Back to attacking the hash- what I need are the three essential parts of the SHA512 hash:
$ml$iterations(int)$salt(hex)$entropy(hex)

All of these are stored in the users’s ShadowHashData, so, I just sudo -i to get a root prompt and pull the ShadowHashData this way:

thebox:~ root# defaults read /var/db/dslocal/nodes/Default/users/administrator.plist ShadowHashData > hexcode

This returns a big hex chunk of data to hexcode which, with a bit of prodding, will give me all three magic bits needed to run a dictionary attack on the password:

(<62706c69 73743030 d101025f 10145341 4c544544 2d534841 3531322d 50424b44 4632d303 04050607 0857656e 74726f70 79547361 6c745a69 74657261 74696f6e 734f1080 3d912bed 387aab30 ad2ce4b4 c37aefa0 3d7dbee0 5ffd0c03 e279674f 60491429 d31303d3 67f1f644 12611459 08e35c41 a9cce934 d394e092 683928b5 b827859d 8b5c8c7f 772b2bc9 b8592987 bfc8b6b5 15476922 f6878ffc ced141b6 1118d173 38f2adc0 0bad4ddb 182b0977 8aeeed1e e4ed479e 8b79d38d 855b5d95 841cbdc4 4f10200a 20f6e408 ad8596ed 4243fc07 75e07d28 aacdd29d fa4ad3e6 3fb3dfd4 08ab0311 7b39080b 22293136 41c4e700 00000000 00010100 00000000 00000900 00000000 00000000 00000000 0000ea>)

First we strip that down to the useful parts using some cli manipulation:
cat hexcode | tr -dc 0-9a-f > trimmed

which gives us a file, trimmed, that looks like this:

62706c6973743030d101025f101453414c5445442d5348413531322d50424b444632d303040506070857656e74726f70795473616c745a697465726174696f6e734f10803d912bed387aab30ad2ce4b4c37aefa03d7dbee05ffd0c03e279674f60491429d31303d367f1f6441261145908e35c41a9cce934d394e092683928b5b827859d8b5c8c7f772b2bc9b8592987bfc8b6b515476922f6878ffcced141b61118d17338f2adc00bad4ddb182b09778aeeed1ee4ed479e8b79d38d855b5d95841cbdc44f10200a20f6e408ad8596ed4243fc0775e07d28aacdd29dfa4ad3e63fb3dfd408ab03117b39080b2229313641c4e700000000000001010000000000000009000000000000000000000000000000ea

next, we need to take that hex and turn it into incomprehensible binary.

The nuances of this and the next step escape me somewhat, as I’m not yet familiar enough with OSX and/or cryptographic schemes in general to understand the under-the-hood workings. I can only assume that the hexdump and it’s binary format are intrinsic to the process, and treat them as a black box. To get the binary version into a new file, hexbin:

xxd -r -p trimmed hexbin

Once you’ve got those bits, you can run another neat little OSX native command to make a human-readable plist:

plutil -convert xml1 hexbin -o admin.plist

And voila, finally getting something we can work with in admin.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SALTED-SHA512-PBKDF2</key>
<dict>
<key>entropy</key>
<data>
PZEr7Th6qzCtLOS0w3rvoD19vuBf/QwD4nlnT2BJFCnTEwPTZ/H2RBJhFFkI
41xBqczpNNOU4JJoOSi1uCeFnYtcjH93KyvJuFkph7/ItrUVR2ki9oeP/M7R
QbYRGNFzOPKtwAutTdsYKwl3iu7tHuTtR56LedONhVtdlYQcvcQ=

</data>
<key>iterations</key>
<integer>31545</integer>
<key>salt</key>
<data>
CiD25AithZbtQkP8B3XgfSiqzdKd+krT5j+z39QIqwM=
</data>
</dict>
</dict>
</plist>

With this we have an iteration integer, and, in base64 again, the entropy and salt values.

Remember, our end goal is to get a hashcat readable hash that I can let my machine run amok against with a password list of some sort. We’re here now:

$ml$31545$salt(hex)$entropy(hex)

salt in b64: CiD25AithZbtQkP8B3XgfSiqzdKd+krT5j+z39QIqwM=
entropy in b64: PZEr7Th6qzCtLOS0w3rvoD19vuBf/QwD4nlnT2BJFCnTEwPTZ/H2RBJhFFkI41xBqczpNNOU4JJoOSi1uCeFnYtcjH93KyvJuFkph7/ItrUVR2ki9oeP/M7RQbYRGNFzOPKtwAutTdsYKwl3iu7tHuTtR56LedONhVtdlYQcvcQ=

So, for our purposes we need to convert those b64 salt and entropy values out of b64 and into their original binary format. Furthermore, we need them in hex to be able to work with them.
Let’s quicken the pace and do it in a single command for each:
echo CiD25AithZbtQkP8B3XgfSiqzdKd+krT5j+z39QIqwM= | base64 -D | xxd -p | tr -d \\n > salthex
echo PZEr7Th6qzCtLOS0w3rvoD19vuBf/QwD4nlnT2BJFCnTEwPTZ/H2RBJhFFkI41xBqczpNNOU4JJoOSi1uCeFnYtcjH93KyvJuFkph7/ItrUVR2ki9oeP/M7RQbYRGNFzOPKtwAutTdsYKwl3iu7tHuTtR56LedONhVtdlYQcvcQ= | base64 -D | xxd -p | tr -d \\n > entropyhex

this gives me a salt hex of 0a20f6e408ad8596ed4243fc0775e07d28aacdd29dfa4ad3e63fb3dfd408ab03
this gives me and an entropy hex of 3d912bed387aab30ad2ce4b4c37aefa03d7dbee05ffd0c03e279674f60491429d31303d367f1f6441261145908e35c41a9cce934d394e092683928b5b827859d8b5c8c7f772b2bc9b8592987bfc8b6b515476922f6878ffcced141b61118d17338f2adc00bad4ddb182b09778aeeed1ee4ed479e8b79d38d855b5d95841cbdc4

Now I can complete my hash string:
$ml$31545$0a20f6e408ad8596ed4243fc0775e07d28aacdd29dfa4ad3e63fb3dfd408ab03$3d912bed387aab30ad2ce4b4c37aefa03d7dbee05ffd0c03e279674f60491429d31303d367f1f6441261145908e35c41a9cce934d394e092683928b5b827859d8b5c8c7f772b2bc9b8592987bfc8b6b515476922f6878ffcced141b61118d17338f2adc00bad4ddb182b09778aeeed1ee4ed479e8b79d38d855b5d95841cbdc4

I write this to a little file, let’s say “machash” and fire up hashcat, specifying hashtype 7100

mod_rewrite, path setup through conf-enabled, .htaccess, alias, and wordpress

In other words, I’ve seriously overcomplicated this setup but after about a half-day of hammering away at it it seems it can be done after all, and my faults were minor.
Important takeaways…

I have a standard apache server setup that serves files from /var/www/html. This is simply defined in my /etc/apache2/sites-enabled directory as a virtual host, like this:

<VirtualHost *:80>
ServerAdmin mog@mogness.net
DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

I have a fully isolated wordpress environment someplace else on my filesystem that I use an alias to patch into the web server with it’s own configuration file. WordPress will write it’s own .htaccess file for you in it’s root, so remove one if you’ve made it, or rename it so you don’t get in the way! It should look something like this:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /alias
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . alias/index.php [L]
</IfModule>
# END WordPress

Most apache installs don’t have mod-rewrite enabled by default, so you ought to take care of that early on. Make sure you’ve got a link in your mods-enabled directory that looks something like this:
lrwxrwxrwx 1 root root 30 Aug 6 14:02 rewrite.load -> ../mods-available/rewrite.load

My over-engineering is the fact that I’ve got it now linked into my apache conf-enabled directory, with a conf file that looks like this:

# this should set up my dev box

Alias /solovic/actual/path/to/my/aliased/webpath.com

<Directory "/actual/path/to/my/aliased/webpath.com">
AllowOverride All
RewriteEngine On
RewriteBase "/actual/path/to/my/aliased/webpath.com"
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ./alias/index.php [L]
#DirectoryIndex index.php
<IfModule mod_php.c>
<IfModule mod_mime.c>
AddType application/x-httpd-php .php
</IfModule>
<FilesMatch ".+\.php$">
SetHandler application/x-httpd-php
</FilesMatch>

php_flag magic_quotes_gpc Off
php_flag track_vars On
php_flag register_globals Off
php_admin_flag allow_url_fopen On
php_value include_path .
</IfModule>
Require all granted
</Directory>

My major fuckup, and what wasted most of my day in this case, was the RewriteRule above in my directory path. I left out that alias bit and so, apache, very confused at why I would want to send everything back to /var/www/html/index.php, kept spitting me 404s. So, if you’ve got a setup like mine and are pulling out your hair, it’s probably related to mod_rewrite, so check your apache error logs. You may come across something like this:

script '/var/www/html/index.php' not found or unable to stat, referer: http://host/aliasdir/wp-admin/post.php?post=10575&action=edit

And that, as they say, is that.