Pandora: A tool for testing the security of password managers

25 December 2024 21 minutes Author: D2-R2

In this article, you’ll discover Pandora, an innovative tool that helps you find vulnerabilities in popular password managers. You’ll learn exactly how the tool analyzes data in your computer’s memory, what risks your accounts may be exposed to, and how you can use Pandora to improve your security.

About the project

This is a red command line tool that helps collect credentials from various password managers. They are divided into three categories: Windows 10 desktop applications, browsers, and browser plugins. It may work on other OSes, such as Linux, but this is not yet tested. In this release (version 1.0), the tool supports 14 password managers with 18 different implementations (for example, the tool can output credentials from a desktop application or a browser plugin of the same product). In particular, in most cases, password managers must be running and unlocked for the tool to work.

The tool can run in full, quick, and local modes. Full mode creates a dump and checks all processes of that password manager. Quick mode checks the most common process that usually contains credentials. Local mode checks the dump file locally. Additionally, local mode has a “merge” option that can help merge multiple dump files into one before performing the analysis. Additionally, the tool can check if a password manager directory exists to help the user determine which password manager is available for use on that host. The tool will only require normal user permissions to obtain a process dump from the password manager. Only the 1Password desktop application requires elevated integrity privileges for the user to be able to take a process dump.

The goal of this tool is therefore to provide an additional attack vector in red team engagements, as many users use password managers. Three different videos were uploaded to demonstrate how the tool works.

Regarding the remediation of these issues, most vendors responded that such issues are beyond their scope, as the attacker would need local access or AV/EDR should protect the user from such attacks. While some products may provide fixes, their exploits will be released later (they are still being disclosed). Two vendors have now acknowledged the issue and provided fixes for CVE-2023-23349 (Kaspersky) and CVE-2024-9203 (Enpass).

This is not an entirely new concept. It has been well known for some time that there is no de facto way to protect desktop applications from such attacks. However, to my knowledge, this is the first time such a tool has been made available to the public. Feel free to provide any feedback and/or suggestions/improvements. The tool only handles relevant versions. Updating a password manager can potentially change the pattern that the tool uses to identify credentials. Built in “c++”

Getting started

Just clone the code and compile it. Visual Studio 2022 was used for the development phase.

  • 1. Install Visual Studio 2022 with all C++ dependencies.

  • 2. Clone the repo.

git clone https://github.com/efchatz/pandora.git
  • 3. Open the project.

  • 4. Create this project as a release.

If you have a problem with “DbgHelp.lib”, follow these steps:

  1. In Project->Properties->Linker->Input, select “All Configurations” from the “Configuration” drop-down list.

  2. Add “DbgHelp.lib” to “Additional Dependencies”.

  3. On the same tab, in “Ignore all default libraries”, select “No”.

  4. Click “OK”.

Methodology

  1. The user selects a mode (full, quick, local). Full mode dumps all processes from the password manager, while quick mode dumps the most common one, which in most cases contains credentials. Local mode is executed locally when a dump file is provided.

  2. The user then has the option to check which password manager is installed for the application or plugin by selecting yes or no. The code checks if the default installation path of each password manager exists and provides the output. Note that during installation, most password managers do not allow the user to change the default installation path. For example, Keeper is installed directly from the MS Store. So this method can help determine which password manager is installed. Note that in full mode, the tool will not check the actual size of each process file that will be created. So, if there is no required free space on the host, some processes will not be created and no error message will be shown.

  1. The user selects the appropriate password manager.

  2. If the user selects “local” mode, they will be asked if they want to merge the different dump files. If so, they must specify their file names, one per line, and type “done” at the end. Otherwise, they will only need to specify the dump file name.

  3. Based on the appropriate password manager, the tool dumps the process into a file.

  4. The dump file is then analyzed to detect any matching pattern within it to retrieve the credentials.

  5. In some cases, the user will be presented with unwanted data. This data will be marked as unparsed characters. Therefore, it is easy to recognize.

  6. The user can then identify the credentials (either in the cmd output or in the corresponding text file).

It should be noted that in some cases, password managers store other types of data in the clear, such as credit card details, addresses, Wi-Fi passwords, etc. Users should be wary of such attacks and not run untrusted files, enable 2FA, etc.

As for exploits, the methodology is simple, i.e. the goal is to identify a pattern or keyword that would accurately indicate the corresponding credentials in the dump file. Every password manager is different, so every method of use is different. However, the concept is the same, i.e. searching for the corresponding pattern can accurately identify the credentials in that file. In some cases, the exploit finds where the credentials start and then collects the next 100 bytes, say. We have done a lot of testing to correctly identify these values, but they may differ in a real-world case. Open an issue if you would like to suggest another password manager to include in this tool that contains the credentials in clear text as part of the process.

Note that the tool will delete the corresponding app.dmp file at the end of execution. Try commenting out this line in your code ‘remove(“app.dmp”);’ if you want to keep the corresponding dump file. It is generally recommended to first execute the code in a restricted environment where the credentials of the main/input code are known, observe the corresponding output, and then execute it on another host.

For more information, please refer to our research paper titled “Close the Memory Dump: Detecting Data Leaks in Password Managers”.

Using

To use this tool, simply run the compiled executable on the appropriate host and enter the name of the password manager. Depending on the password manager, there are certain requirements for the tool to be able to retrieve the credentials. However, in most cases, we kept password managers that required basic interaction to save their credentials in the memory of their process. Once launched, the tool will automatically create a dump of the appropriate process based on the selected password manager, print the credentials to cmd, and save them to a file (the file location is the current .exe folder).

To understand how this tool works, three videos have been uploaded. The videos show the phase in which an attacker can retrieve credentials from a password manager. In the case of Avira and similar password managers, this can be done without any user interaction (watch the corresponding video).

The table below provides a general idea of ​​the tool’s capabilities. Note that Firefox and related Firefox password manager plugins may not work properly. They require additional research to ensure that the tool can retrieve credentials in every case. This is because Firefox changes its template with each execution.

Note: The “Users” column refers to the number of users listed in the Chrome Web Store for each browser plugin. Browser plugins were tested using Chrome v129.0.6668.89/.90. Later versions of Chrome may interfere and change the template of each browser plugin.

Regarding credential extraction, some exploits rely on a certain number of bytes to extract credentials. So, in some cases, this number may need to be increased to get this information correctly. Common usernames and passwords were used in the experiments. So, in most cases, this will be sufficient.

Another note concerns the version of each browser plugin password manager. If there are changes made to the code that affect the process, the tool may not detect these credentials. So, be aware that there is a possibility of some credentials being mishandled if you are using an older/newer version of the tool or running a different OS (tested on Windows 10 Pro).

In most cases, to obtain credentials you will need:

  1. The corresponding application (browser or desktop application) is running, unlocked, and working.

  2. In some cases, such as Chromium browsers, you need to interact with either a corresponding plugin or the browser’s built-in password manager.

  3. In other cases, some password managers store these credentials in clear text in memory even after locking. This behavior has been observed with Keeper.

  4. In the case of 1Password, a high level of integrity is required. So, run the .exe with elevated privileges or provide a dump file as input.

  5. All tests were performed with each password manager’s default settings.

Suffice it to say that since the user behavior is to open such applications and leave them open, this will provide an additional attack vector for lateral movement. Another key point is that most of these tools are automatically blocked when the user is completely inactive. This means that even if the application or browser plugin is inactive and the user is using their host for other activities, these applications will not be blocked. Also, in some cases, user interaction can be avoided completely. For example, some browser plugins remain unlocked for some time. As a result, it is possible to start this process from cmd without requiring the user and extracting credentials. Watch the Avira video example to understand this process.

It should be noted that in some cases, such as KeePass, StickyPassword and Opera, no credentials were found in memory as clear text.

We are working on releasing a scientific paper that will describe the experiments and any other relevant details.

prerequisites

This section is dedicated to any prerequisites that the tool will need in order to be able to reset credentials from a password manager.

1Password

The 1Password process requires high integrity privileges so that the tool can dump the process and retrieve the credentials. To retrieve the credentials, the application was opened, the master password was entered, and after waiting at least 1 minute, the tool was launched to reset the credentials. The following screenshot illustrates the execution of the tool when the application is launched. The hidden data is related to the master password. Note that the output may contain extra characters at the end of the returned string; in the screenshot, only the last character is not included in the master password. It should also be noted that the tool cannot retrieve the master password if the user has inserted it into the appropriate field. For some reason, 1password does not store the master password in the process if the user has inserted it. Regarding the 1Password plugin, the master credentials are available.

Avira

The video has been paused to reduce the size. First, Chrome opens with cmd, then waits for at least 1 min. This means that the attacker can start the Chrome process without any user interaction, since Avira does not require the user to enter the master password. After that, Pandora was launched, followed by a wait to retrieve the credentials. The tool looks for matching entries. As you can see, each entry is displayed on a separate line, i.e. the site name, the password, and the corresponding username. Note that headless mode does not run browser plugins. So, for this attack to work, Chrome must be visible.

Bitdefender

Bitdefender only stores entries when they are needed, for example, when the user visits a URL that belongs to the entry. However, the master password is stored after the user enters it. As a result, there is a case where the attacker can reset the master password. The tool does not check the entries, only the master password.

Bitwarden

Bitwarden imports all entries immediately after unlocking the vault. Some entries will appear multiple times as the tool finds them and creates a dump from the dump file.

Only the master password and username are available to the application. It should be noted that the application clears the master password from memory after some time (approximately 10 minutes). The following screenshots illustrate the retrieval of the master password (returned twice) and username data.

NordPass

NordPass stores the master username and password. Thus, both can be retrieved from the memory of the corresponding process. For the master password, only one pattern will be returned. For the username, the following screenshot illustrates the result.

Chrome, Brave and Opera

Both browsers have the same behavior, they store the username and password of the login form they interact with, and they have saved the credentials, but to get all the records, the user has to visit the browser’s password manager feature or the attacker has to open the browser and visit that page. Change the keyword to search for a specific website or email address in the process. Also, all Chromium browsers can be launched without user interaction. For example, a VBS script (not OPSEC) can be used to launch the browser and visit “chrome://password-manager/passwords”. The tool can then extract all the records, as shown in the following screenshot:

Note that the password manager page only needs to be visited once, meaning that even if the password manager is closed and the browser is not terminated and another process is started, the credentials will be stored in memory. Otherwise, the user will visit the web page where the password manager saved their credentials, and then those credentials will be stored in the process.

MSEdge

MSEdge is different, meaning that only the browser needs to be open. It is not necessary for someone to visit the password manager page. MSEdge seems to preload the password manager immediately upon opening. As a result, the tool can extract all records, with the same output as in the other two browsers.

Dashlane

When Dashlane is unlocked and interacted with in any way, the records will be available for the next 1 minute. After that, only the master password remains in the process. Depending on the case, the tool will collect the relevant credentials, as shown in the following screenshots. The first screenshot illustrates the case where the master password is available, and the second screenshot illustrates the case where the records are available.

Enpass

In the case of Enpass, the application automatically selects the last entry that the user clicked on before closing the application. As a result, it is possible to retrieve this entry from the process with minimal user interaction (simply by opening the application). It should be noted that sometimes the application does not automatically select the last entry when the user opens it. Therefore, to speed up the recording process, the user manually selects the entry. This issue has been resolved in v6.11.3.

Firefox

Firefox uses a different pattern each time it loads credentials, either from the built-in password manager or from another browser plugin. For this reason, the search is done based on regular email addresses that are also used as usernames, such as “@gmail.com”. The code will search for this string and print some matching data before and after it. It should be noted that the user can include additional strings (check the getCredsfirefox2.h file), but the output will be huge (especially if the user resets all processes). Therefore, it is suggested to use separate strings for each analysis: starting with “@gmail.com” to identify any set of credentials, and then moving on to another string, such as “@yahoo.com”, to identify any possible password in the process. Typically, to access saved credentials, the user must visit the password manager page or visit the saved web page where the password manager saved the set of credentials. In the latter case, the process will only contain the credentials of that account. For example, if a user has saved their “Facebook” credentials and visits that web page, the process will only contain the “Facebook” credentials. Finally, Firefox has no problem starting from cmd with a command like “run firefox about:logins”.

Ironvest

For Ironvest, the corresponding web application must be launched. Since this password manager does not require a master password upon opening and provides automatic login, Chrome was launched via cmd and “ironvest.com/app” was opened. After that, the tool was used to extract all the entries. The problem is illustrated in the screenshot below: the entries are saved multiple times, as they are created each time the tool finds them in the dump file. Note that if the user or attacker does not visit the Ironvest dashboard page, the entries are not loaded in the process. Another way to obtain the entry is for the user to visit the URL of the saved entry. The autofill feature will retrieve these credentials during the process, but only for that entry. It should be noted that Ironvest deletes the entries from the process after about 2-3 minutes. Additionally, the passwords appear to be contained between a specific three characters and end with a comma.

Kaspersky

In Kaspersky, the exploit only worked for the Chrome browser. When a user opened their browser and enabled the autofill option, the password manager’s Native Messaging Server process stored each entry in plain text format and did not clean up the process. So, if an attacker has access to this host and waits for at least 1 minute, they can exploit this issue and retrieve any saved entry from this process.

Keeper

For Keeper, the program was launched, the master password was entered, and the tool was activated. The tool’s response was as follows:

The tool will extract all records and the user’s master username and password. If the record is empty, it means that this user has no other records in the vault. For example, if the tool prints 5 records, 4 of which contain data and 1 without data, then the user has stored 4 records in the password manager.

LastPass

LastPass automatically logs the user into the vault when the Chrome browser is opened. So, to retrieve the master password, the user has to log out and log in manually (by entering the master password) without closing the browser. In every other case, all the entries and the master username should be retrieved. The video shows how LastPass was run via cmd. The tool dropped all the entries and the master username along with some junk data that matched the given search pattern. It is recommended to check the .txt file as it makes it easier to identify the credentials as the console will contain some junk lines.

Norton

Norton uses keywords to store credentials. So, the following screenshot illustrates the credentials that the tool dropped. The important fact was that Norton Password Manager automatically stored the username and password of the Norton user account in the vault. So, since all the relevant entries are available, if the user has not deleted the entry with his Norton account username/password, the tool will also extract them. These are the credentials that were removed from the console output. Wait 30 seconds after launching the browser to retrieve the credentials using the tool. This corresponding version asks the user to enter the master password every time they open the browser.

Passwarden

The usual procedure was required. As you can see from the following screenshot, all the data is marked with different keywords:

In the new version of the tool, the master username can also be retrieved from the password manager. The master password also exists in plain text format in the process, but there is no stable way to extract it yet.

The video has been paused to reduce its size. At the beginning, Passwordboss is launched, the master password is entered, and the program is minimized. After that, the tool is executed and waits for 3-4 minutes. As you can see, the tool retrieved all the matching records. Some of them, like Amazon, were empty, but others, like Facebook, Google, and a special one called aegean, were filled with the user’s username and password. Typically, records with data contain the character “[]”.

Roboform

Roboform automatically unlocks the storage when the user opens the Chrome browser. Specifically, Roboform requires interaction with any saved record URL or for the user to click a plugin to load the records. This way, you can start the Chrome process from cmd or powershell, and then run the tool to extract the credentials. Alternatively, the master password is available by simply opening the browser. The following screenshot shows the credentials that the tool dropped after launching Chrome from cmd. The first screenshot illustrates the output of the extracted records, while the second demonstrates the extraction of the master password.

With the Roboform app, everything is easier. If the program is running, all records can be extracted. In particular, the records will be available as saved in the password manager. This means that all possible records will be returned along with those that the user has saved. Below is an example of extracted login passwords.

Repetitiveness

As for repetitiveness, the current versions of the application do not require any additional adjustments. As a result, only pattern-based extraction can help in identifying and extracting the required information. However, for completeness, the code below demonstrates the use of Repetitiveness in Roboform v9.5.2.0. First, we need to count how many times a set of credentials is displayed in plain text format in the application process. We can then use this countOccurrences function to count how many times a particular set of credentials is stored in the process. After that, we can use the getCredsroboformapp4 function to open the extracted data file and check how many times each line of text exists in the process. If the number of times in countOccurrences equals the number of times the entry was displayed in the process, then we can print that line of text. The goal here is to reduce the output of the extracted text and easily identify the set of credentials. In the current example, the original pattern extraction text was 136 lines. After using recurrence, only the master password was retained.

#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include "../../core/saveFile.h"

//Repetitiveness for Roboform
// Helper function to find occurrences of a sequence in the file data
int countOccurrences(const std::vector<unsigned char>& data, const std::vector<unsigned char>& sequence) {
    int count = 0;
    auto it = data.begin();
    while (it != data.end()) {
        it = std::search(it, data.end(), sequence.begin(), sequence.end());
        if (it != data.end()) {
            ++count;
            ++it; // Move iterator to continue search after this match
        }
    }
    return count;
}

int getCredsroboformapp4(std::string filename) {
    //Due to using saveFile2 in getCredsroboformapp2.h
    std::ifstream sequencesFile("credentials2.txt");
    std::ifstream dataFile(filename, std::ios::binary);

    if (!sequencesFile.is_open()) {
        std::cerr << "Error opening the sequences file." << std::endl;
        return 1;
    }

    if (!dataFile.is_open()) {
        std::cerr << "Error opening the data file." << std::endl;
        return 1;
    }

    // Read the entire data file into memory
    std::vector<unsigned char> fileData((std::istreambuf_iterator<char>(dataFile)), std::istreambuf_iterator<char>());
    dataFile.close();

    std::string line;
    while (std::getline(sequencesFile, line)) {
        // Convert the line to a sequence of unsigned char
        std::vector<unsigned char> sequence(line.begin(), line.end());

        // Count occurrences of the sequence in the file data
        int occurrences = countOccurrences(fileData, sequence);

        // Print and save the results only if found exactly once
        if (occurrences == 1) {
            std::cout << "Sequence: " << line << " found " << occurrences << " time." << std::endl;
            saveFile(line + "\n");
        }
    }

    sequencesFile.close();

    return 0;
}

This tool is provided as is for educational purposes and/or legal evaluation.

Other related articles
Found an error?
If you find an error, take a screenshot and send it to the bot.