Skip to Main Content
October 20, 2022

The Curious Case of the Password Database

Written by Travis Kaun

Nowadays, password managers are king. We use password managers to secure our most sensitive credentials to a myriad of services and sites; a compromise of the password manager could prove devastating.

Due to recently disclosed critical Common Vulnerabilities and Exposures (CVEs) involving ManageEngine's Password Manager Pro software, a client came to us at TrustedSec, wondering: If an attacker gained access to our Password Manager Pro server, would our passwords be compromised?

Scooby Doo meme

Since the client was assured that data within the Password Manager Pro server was encrypted, our answer was assuredly, "No." Right? We set off to find out!

The recent CVEs affecting the Password Manager Pro software were some of the worst kind: Remote Code Execution (RCE). For the sake of this engagement, we were focused not so much on the initial attack vector, but rather on the extent of the post-exploitation possibilities. Simply, with access to the system's data, could we recover the encrypted secrets stored within?

We started with access an attacker would presumably have:

Note: Mid-engagement, we identified some newly published work by smaury at Shielder regarding tearing apart Password Manager Pro. The timing was astounding. Our collective articles may look similar; but our approaches, experience, and code differ. We highly suggest checking out his terrific write-up regarding this topic.

Step 1 - Application Enumeration

We staged an instance of Linux running ManageEngine’s Password Manager Pro version 10.5 to replicate the client's environment. After fetching the application software and initiating a restore, we started by analyzing the running processes and identifying key information. The application was running Java and PostgreSQL as the primary components.

Figure 1 - ManageEngine's Running Processes

TrustedSec then explored the Password Manager Pro application directory, revealing a collection of Java JAR application and configuration files. By reading application documentation, TrustedSec identified the username and encrypted database password stored in the database-params.conf file.

Figure 2 - Encrypted Database Password

The pmp_key.key file reveals the PMP key, which will come in handy later.

Figure 3 - PMP Key

Step 2 - PostgreSQL Password Recovery

One of the best parts of working at TrustedSec is being surrounded by a diverse and talented team of people who are willing and able to help. My Java skills didn't make it much past my sophomore year of college; however, my skilled coworker Rob Simon was able to hop in and provide additional guidance.

We extracted the application JAR files located in /opt/ManageEngine/PMP/lib and decompiled and analyzed the files to reveal how decryption functions for the underlying PostgreSQL database were handled. While walking through the code, we found that the application uses a static secret key derived from the string @dv3n7n3tP@55Tri that was used to encrypt the database password—notably, only five (5) characters: 7n3tP.

Figure 4 - JAR Decompilation
Figure 5 - Password Manager Pro Hardcoded Password – 7n3tP
Scooby Doo meme unmasking

Using the decryptPassword function, we could then whip up a bit of Java code using Password Manager Pro’s own functions to conduct the decryption for the database password. This revealed our PostgreSQL database password.

Figure 6 - Database Decryption Function

Hey, that's a plaintext database password!

Figure 7 - Recovered Database Password

Step 3 - Database Interrogation - Master Key

TrustedSec investigated the PasswordEncryptDecrypt class to determine how encrypted passwords could be recovered. A master key is required to decrypt database passwords. To obtain the decrypted master key, TrustedSec identified the encrypted master key stored within the database as notesdescription and supplied the pmp_key to the decryptPassword function of the PMPEncryptDecrypt class. This resulted in the plaintext master key.

To pull the encrypted master_key, within Postgres, issue:

select * from Ptrx_NotesInfo

Figure 8 - Encrypted Master Key (notesdescription)

Then plug the newly acquired encrypted master_key into our Java script to derive the plaintext master key. Groovy, we got a plaintext master!

Figure 9 - Master Key Decryption Function
Figure 10 - Recovered Master Password

Step 4 - Database Interrogation - Encrypted Passwords!

To harvest the data of interest stored within PostgreSQL, you can use the following query. Notice that the decryptsblob table will still be encrypted. One last decryption step will be needed.

select decryptschar(PASSWORD,'<INSERT master_key>') from ptrx_passbasedauthen

Around this time in our analysis, I stumbled upon the previously mentioned research from smaury @ Shielder . He included a robust query that was great for pulling with additional table columns.

select ptrx_account.RESOURCEID, ptrx_resource.RESOURCENAME, ptrx_resource.RESOURCEURL, ptrx_password.DESCRIPTION, ptrx_account.LOGINNAME, decryptschar(ptrx_passbasedauthen.PASSWORD,'***master_key***') from ptrx_passbasedauthen LEFT JOIN ptrx_password ON ptrx_passbasedauthen.PASSWDID = ptrx_password.PASSWDID LEFT JOIN ptrx_account ON ptrx_passbasedauthen.PASSWDID = ptrx_account.PASSWDID LEFT JOIN ptrx_resource ON ptrx_account.RESOURCEID = ptrx_resource.RESOURCEID

Data should look similar to the image below, which I then exported via DBeaver.

Figure 11 - Database Extraction - Encrypted Passwords

Step 5 - Password Recovery

Now, we have the decrypted database password and the master key, but we still have an encrypted password column within the database. Using the same PasswordEncryptDecrypt class that we examined earlier, we can build a script where we supply an encrypted password along with pmp_key to reveal the stored plaintext credential.

Leveraging the expertise of the TrustedSec resident Python wizard, Charles Yost, we opted to script this in Python versus working in Java because, honestly, who prefers Java?!

On that note, we’re happy to announce the release of Zoinks – the Password Manager Pro Decrypter!

The script can be operated in interactive mode or supplied parameters at runtime.

Step 1 - Provide the following:

  • Encrypted Database Password (database_params.conf)

Step 2 - Once the database has been accessed, provide the following:

  • Password Manager Pro Key (pmp_key.key)
  • Encrypted Master Key (notesdescription)
  • Encrypted Password (decryptsblob)

Let’s go after HackingDave’s password and plug it into our zoinks.py script.

Figure 12 - Zoinks Decryption Toolkit

Conclusion

In the midst of a breach, we often hear, "Don't panic—the data on the server was encrypted!" Data encryption is a best practice; it checks the audit box, and it allows us to sleep soundly. During this engagement, the more we peeled back layers of the Password Manager Pro application, the clearer it became that, while data was encrypted, everything needed to decrypt the data was stored on the server.

TrustedSec determined that someone with access to a Password Manager Pro server could recover encrypted data stored within the server due to ManageEngine’s implementation of encryption keys and methods.

Shoutout to my TrustedSec team (Rob, Charles, and Phillip) for the time and guidance and to smaury for the timely write-up!

Scooby Doo meme

Update (November 3, 2022)

TrustedSec determined that someone with access to a Password Manager Pro server could potentially recover encrypted data stored within the server if conditions are met. TrustedSec suggests clients using ManageEngine’s PMP review their best practices to securely manage key files to prevent this type of attack.