FreeIPA and Red Hat IdM Password Auditing

Fingerprint Icon

FreeIPA and IdM

FreeIPA is an open source project that provides a centrally managed identity, policy and audit system. It is also the basis of Red Hat Identity Management(IdM). Both of them use 389 Directory Server, also known as 389-ds as the LDAP backend.

In simple terms, they can be viewed as Linux-based alternatives to Active Directory, and are based around the same code technologies (DNS, LDAP, Kerberos). Much like Active Directory, they provide central authentication for user and servers within the environment.

While password auditing for Active Directory accounts is a well-established process (and discussed in a previous article), password auditing methods for FreeIPA or Red Hat Identity Management are less well known, and as such may be overlooked or forgotten

Extracting Hashes Through LDAP

Password hashes are stored in the LDAP database, and can be queried through LDAP with the appropriate permissions. By default, only the “Directory Manager” account would have permission to access these.

The names for each of the user accounts are stored in a few different fields, including the full Kerberos names in krbCanonicalName, the primary usernames in uid, and the friendly names in cn.

The password hash will be stored as base64 in the userPassword attribute. However, there may also be a second attribute called ipaNTHash, which is used to store an NT hash of the password (for compatibility with Windows systems).

Using the Directory Manager account, the hashes can be extracted using ldapsearch, as shown in the example below:

$ ldapsearch -D "cn=Directory Manager" -x -w "Password123" "(userPassword=*)" krbCanonicalName uid cn userPassword ipaNTHash
[...]
# admin, users, accounts, example.local
dn: uid=admin,cn=users,cn=accounts,dc=example,dc=local
krbCanonicalName: [email protected]
uid: admin
cn: Administrator
userPassword:: e1BCS0RGMl9TSEEyNTZ9QUFBSUFPWkx6YmJoY1llWTFnMnpwNnZid1hoVHdSSWx
 BNjhHK01OUXd1RitZeVRBSWptemU5V1A5alZIYkR2bGVLUUlBQ0ZvSFFVQ1Z3TXZrckc0QUlNY3d4
 VFRxejQ4VkNxd1c3enl6SGs4M1RsQUVFZDkzcVBkV01CUFZUdnV3SjBmWU5GZkJGc1ozNTlETlQ1T
 HVOZXJFWjkxVWo5aGd5Vy9uQVNGck5jTllGbGZsVDAxbFpFRDFJUld0SUpLcUswRzFNbzBXeDlUT0
 pBU0k5Y0FYWTZRWEV6MGRqek96TkFuc1RIZk1sd2k2bndubXVES0tQaWFCMVRhay9QQW1nSjJEcDF
 yQjV1QmxuTiszUXE2dEZJenBhMmxxNTl2WGp0SUEzVURDczd4b0xvRHRFUC9RY3IxVTV5b1NwZFFT
 aHBFdjlsTjZHT0NLZDJCcmlHaEhHQTdMYWtqeXpYSktKN1dYRC9CSlcvYjVCMThOWW9pWk95MEFTU
 mJDRHF5enZQeURzL3N3aUc2c3YyejBrWnI1bWoxYm8rcnBvMFVWVXRQWk9NRXNVV0tXMUp1
ipaNTHash:: WKR4E1qTrDvwWKXqDo/bcQ==
[...]

 
The output isn’t particularly nice (with the userPassword being split across multiple lines) - but it’s given us the information that we need.

Extracting Hashes from LDIF Files

Alternatively, if we have root privileges on the underlying server, we can extract this information directly from the filesystem. The dbscan tool (part of the 389-ds-base package) can be used to dump out the contents of the LDIF files in the same format as ldapsearch. Note that the path will change slightly depending on the name of the domain (“example.local” in this case):

$ dbscan -f /var/lib/dirsrv/slapd-EXAMPLE-LOCAL/db/userRoot/id2entry.db
[...]
id 39
[...]
        uid: admin
        krbPrincipalName: admin@EXAMPLE.LOCAL
        ipaNTHash:: WKR4E1qTrDvwWKXqDo/bcQ==
        userPassword:: e1BCS0RGMl9TSEEyNTZ9QUFBSUFPWkx6YmJoY1llWTFnMnpwNnZid1hoVHdSSWx
         BNjhHK01OUXd1RitZeVRBSWptemU5V1A5alZIYkR2bGVLUUlBQ0ZvSFFVQ1Z3TXZrckc0QUlNY3d4
[...]

 
This will generate a lot of output, so it should be redirected to a file.

Hash Formats

Once we’ve extracted this information from the LDAP database, we need to parse it into a format that we can actually use.

NT Hashes

The NT hashes stored in the ipaNTHash fields are based64 encoded, rather than the more typical ASCII hex encoding. They can be easily converted into a crackable format by base64 decoding them, and then re-encoding them as ASCII hex:

>>> import base64
>>> base64.b64decode('WKR4E1qTrDvwWKXqDo/bcQ==').hex()
'58a478135a93ac3bf058a5ea0e8fdb71'

 
NT hashes are much easier (computationally) than any of the other hash formats used - so they should be your first priority when trying to crack the hashes. These can be cracked using the NT format with John.

Salted SHA

The main userPassword field is base64 encoded, and by decoding it, we can obtain the underlying hash.

One of the common formats that is used to store password hashes is salted SHA-512, also known as SSHA512. There are indicated by the {SSHA512} prefix, as shown in the example below.

{SSHA512}SCMmLlStPIxVtJc8Y6REiGTMsgSEFF7xVQFoYZYg39H0nEeDuK/fWxxNZCdSYlRgJK3U3q0lYTka3Nre2CjXzeNUjbvHabYP

 
This can then be cracked using the SSHA512 format in John.

PBKDF2

Newer versions of FreeIPA or IdM use the more secure PBKDF2 algorithm for storing passwords, with a slightly unusual hash format. When the userPassword field is base64 decoded, you get a blob such as:

{PBKDF2_SHA256}AAAIAOZLzbbhcYeY1g2zp6vbwXhTwRIlA68G+MNQwuF+YyTAIjmze9WP9jVHbDvleKQIACFoHQUCVwMvkrG4AIMcwxTTqz48VCqwW7zyzHk83TlAEEd93qPdWMBPVTvuwJ0fYNFfBFsZ359DNT5LuNerEZ91Uj9hgyW/nASFrNcNYFlflT01lZED1IRWtIJKqK0G1Mo0Wx9TOJASI9cAXY6QXEz0djzOzNAnsTHfMlwi6nwnmuDKKPiaB1Tak/PAmgJ2Dp1rB5uBlnN+3Qq6tFIzpa2lq59vXjtIA3UDCs7xoLoDtEP/Qcr1U5yoSpdQShpEv9lN6GOCKd2BriGhHGA7LakjyzXJKJ7WXD/BJW/b5B18NYoiZOy0ASRbCDqyzvPyDs/swiG6sv2z0kZr5mj1bo+rpo0UVUtPZOMEsUWKW1Ju

 
This hash is using PBKDF2 with HMAC SHA-256. However, rather than the typically human-readable format, the salt and iterations are base64 encoded and stored as part of the string. Decoding the base64 into a byte array gives us the following format:

  • Iterations = 4 bytes
  • Salt = 64 bytes
  • Output = 256 bytes

Based on this, we can split, decode, and re-encode this hash into a format that John supports. Note that John uses a slightly different version of base64 than usual (with the + symbol being replaced by the .). This gives us the following hash:

$pbkdf2-sha256$2048$5kvNtuFxh5jWDbOnq9vBeFPBEiUDrwb4w1DC4X5jJMAiObN71Y/2NUdsO.V4pAgAIWgdBQJXAy.SsbgAgxzDFA$06s.PFQqsFu88sx5PN05QBBHfd6j3VjAT1U77sCdH2DRXwRbGd.fQzU.S7jXqxGfdVI/YYMlv5wEhazXDWBZX5U9NZWRA9SEVrSCSqitBtTKNFsfUziQEiPXAF2OkFxM9HY8zszQJ7Ex3zJcIup8J5rgyij4mgdU2pPzwJoCdg6dawebgZZzft0KurRSM6Wtpaufb147SAN1AwrO8aC6A7RD/0HK9VOcqEqXUEoaRL/ZTehjgindga4hoRxgOy2pI8s1ySie1lw/wSVv2.QdfDWKImTstAEkWwg6ss7z8g7P7MIhurL9s9JGa.Zo9W6Pq6aNFFVLT2TjBLFFiltSbg

 
However, there’s a problem: John won’t accept this hash. The reason for this is that PBKDF2-HMAC-SHA256 would normally have an output length of 256 bits (32 bytes), matching the output size of the SHA-256 algorithm. However, PBKDF2 allows a custom output length (the dkLen parameter), and the developers of 389-ds chose to have an output length of 256 bytes - which is longer than John supports. The comments in the file state that this is because “NSS explodes without setting an error code” if the length isn’t 256 bytes.

Because of the way that PBKDF2 works (explained in this detailed answer on StackExchange), the derived key (i.e, the output, or what would commonly be called the “hash”) is constructed from multiple blocks, which are calculated indepdenently. This means that we only need to attack a single block to obtain the password.

Since SHA-256 is being used as the pseudo-random function (PRF), the block size is 256 bits (32 bytes). This means that we can just take the first 32 bytes of the output, which gives us a hash such as the one below:

$pbkdf2-sha256$2048$5kvNtuFxh5jWDbOnq9vBeFPBEiUDrwb4w1DC4X5jJMAiObN71Y/2NUdsO.V4pAgAIWgdBQJXAy.SsbgAgxzDFA$06s.PFQqsFu88sx5PN05QBBHfd6j3VjAT1U77sCdH2A

 
This can then be cracked using the PBKDF2-HMAC-SHA256 format in John

Automating the Process

Doing this process manually and efficiently becomes tedious and impractical, but it can easily be automated. The extract_ldap_hashes.py script can be used to convert the output from either ldapsearch or dbscan into a format that can be interpreted by John. The script parses the text output (rather than using the Python LDIF library), in order to avoid any dependencies outside of the standard library.

Once the hashes have been extracted, the next step is to crack them with John. This can start with single steps such as single crack mode, as discussed in the hash cracking section of the Active Directory Password Auditing guide. When cracking, it’s generally sensible to focus on the faster hash types (NT and SSHA) before slower types like PBKFD2.