Click here to Skip to main content
15,883,883 members
Articles / Programming Languages / C

The Secrets of Firefox Credentials

Rate me:
Please Sign up or sign in to vote.
5.00/5 (13 votes)
30 Jan 2017CPOL5 min read 25.1K   14   5
Way to fetch stored credentials in more recent versions of Firefox
Firefox is the most secured web browser. Finding a way to fetch its stored credentials wasn't easy, especially when it comes to the more recent versions. However, there is a way and it is shown in this article.

Introduction

This article is the fourth of several articles covering the secrets of obtaining stored (and encrypted) credentials stored by browses (and other applications, for example: MS Outlook). The first article covered Wi-Fi credentials. The second one covers Chrome's credentials. The third article covers Internet Explorer's credentials. This article is the most challenging one. It covers Firefox and explains how credentials are stored by it and can be fetched from it.

What Makes Firefox Secure

Firefox has become much more secure in recent versions compared to previous versions but also compared to other browsers. In the past, it was enough to fetch the signons.txt file located in the Firefox profile directory and find all stored credentials there. From version 3.5, the textual format has been replaced with a combination of SQLite database and JSON file (namely ‘logins.json’). In addition, if a “master key” is set, there is no way to decrypt the stored credentials without knowing this key first. When a master key isn't set, you can find the data in logins.json and decrypt the credentials. Both user and password for each credential are encrypted using PK#11.

Locating Firefox Profile Path

First, we need to find the location of the data we are going to fetch, which is the Firefox Profile path. That would normally be in c:\users\<your user account>\appdata\local\Mozilla\Firefox\\profiles.ini.

C++
std::wstring GetFirefoxProfilePath()
{
    wchar_t strAppData[MAX_PATH];
    SHGetSpecialFolderPath(NULL, strAppData, CSIDL_APPDATA, TRUE);

    wchar_t strIniPath[MAX_PATH];
    swprintf_s(strIniPath, MAX_PATH, L"%s\\Mozilla\\Firefox\\profiles.ini", strAppData);

    wchar_t strRelativePath[MAX_PATH];
    GetPrivateProfileString(L"Profile0", L"Path", 
                            L"", strRelativePath, MAX_PATH, strIniPath);

    wchar_t strFullPath[MAX_PATH];
    swprintf_s(strFullPath, MAX_PATH, 
               L"%s\\Mozilla\\Firefox\\%s", strAppData, strRelativePath);

    wchar_t strShortPath[MAX_PATH];
    GetShortPathName(strFullPath, strShortPath, MAX_PATH);

    if (!PathFileExists(strShortPath))
    {
        return L"";
    }
    return ((std::wstring)strShortPath);
}

Mapping the nss3 DLL

The nss3.dll is used by a set of libraries called Network Security Services (NSS). These libraries were designed to support cross-platform development of communications applications that support SSL, S/MIME, and other Internet security standards. For a general overview of NSS and the standards it supports, see this page.

Since this article is about implementation for Windows, I will only mention the Windows used libraries:

  • nss3.dll - Windows shared library
  • nss3.lib - Windows import library binding to nss3.dll
  • nss.lib - Windows static library

So first, we need to map the functions in nss3.dll which we intend to use.

C++
fpNSS_Init = (NSS_Init_p)GetProcAddress(moduleNSS, "NSS_Init"); 
fpNSS_Shutdown = (NSS_Shutdown_p)GetProcAddress(moduleNSS, "NSS_Shutdown"); 
fpPL_ArenaFinish = (PL_ArenaFinish_p)GetProcAddress(moduleNSS, "PL_ArenaFinish"); 
fpPR_Cleanup = (PR_Cleanup_p)GetProcAddress(moduleNSS, "PR_Cleanup");
fpPK11_GetInternalKeySlot = 
  (PK11_GetInternalKeySlot_p)GetProcAddress(moduleNSS, "PK11_GetInternalKeySlot");
fpPK11_FreeSlot = (PK11_FreeSlot_p)GetProcAddress(moduleNSS, "PK11_FreeSlot");  
fpPK11SDR_Decrypt = (PK11SDR_Decrypt_p)GetProcAddress(moduleNSS, "PK11SDR_Decrypt"); 
PK11_CheckUserPassword = 
  (PK11CheckUserPassword)GetProcAddress(moduleNSS, "PK11_CheckUserPassword");

The Master Password

Firefox brings a new security measure named the Master Password. The Master Password is a centralized encryption key used to encrypt all stored credentials. This key is hashed but not stored anywhere so it's impossible to find it.

Decrypting Credentials Programmatically When the Master Password Is Known

I have made some tests trying to see what needed to be done to decrypt credentials stored by Firefox when a Master Password is set. First, it should be explained how to decrypt credentials programmatically when the Master Password is known.

Guessing the Master Password

Alternatively, a hacker might use brute-force techniques trying to guess the Master Password. That can be done by either running over all possible combination of strings (or alpha numeric strings) having the length of 1-7 characters (a longer password will be almost impossible to break using this method). Another method would be running over a list of commonly used password. This method is called a "dictionary".

The Code Needed to Examine a Given String

The following code checks if "MyGuess" is indeed the Master Password. If it is, running the rest of the code of our tool will decrypt all stored passwords.

C++
bool GuessMasterPassword(char *MyGuess)
{
    bool result = FALSE;

    PK11SlotInfo *pK11Slot = fpPK11_GetInternalKeySlot();
    if (PK11_CheckUserPassword(pK11Slot, MyGuess) == SECSuccess)
    {
        result = true;
    }
    (*PK11FreeSlot) (pK11Slot);
    return result;
}

If the return result of GuessMasterPassword is true, then we can proceed.

Decrypting the Credentials

The next part of our code will decrypt any encrypted part of a credentials entry and should be used regardless of the Master Password. If there is no Master Password set, this code still needs to be executed, and if there is a Master Password set, we assume that GuessMasterPassword has returned 'true' for any reason (you know it, you guessed it or you brute forced it).

C++
LPSTR DecryptString(LPSTR strCryptData)
{
    if (strCryptData[0] == 0x0)
        return FALSE;

    DWORD dwOut;
    LPSTR strClearData = "";
    LPBYTE lpBuffer = base64_decode((char*)strCryptData, strlen(strCryptData), (int *)&dwOut);
    PK11SlotInfo *pK11Slot = fpPK11_GetInternalKeySlot();

    if (pK11Slot)
    {
        SECItem pInSecItem, pOutSecItem;;
        pInSecItem.data = lpBuffer;
        pInSecItem.len = dwOut;

        pOutSecItem.data = 0;
        pOutSecItem.len = 0;

        if (fpPK11SDR_Decrypt(&pInSecItem, &pOutSecItem, NULL) == 0)
        {
            strClearData = (LPSTR)malloc(pOutSecItem.len + 1);
            memcpy(strClearData, pOutSecItem.data, pOutSecItem.len);
            *(strClearData+pOutSecItem.len) = '\0';
        }

        fpPK11_FreeSlot(pK11Slot);
    }
    return strClearData;
}

Handling Firefox Date/Time

To be able to process records from various browsers, each of them uses its own method for storing dates and times. We need to convert each date/time record into a single format which we can later use for manipulations such as finding all credentials from a given date, or since the last time we checked. When it comes to Firefox, it stores its dates in large integer. This number is called Epoch Time. You can enter an Epoch Time to this web site and see the date it represents and vice versa.

The code used for our tool intends to generate a CTime, so our Windows MFC based tool can process the various dates after converting them to this Windows date/time format. Doing that is possible by converting any given date/time (or long integer) into two intermediate formats: FILETIME and SYSTEMTIME. The input of our function will be std::string since it is easier to read an XML or JSON items to a string first.

C++
SYSTEMTIME FirefoxTimeToSysTime(string FirefoxTime)
{
    __int64 unixtime = atol(FirefoxTime.c_str());
    __int64 longLongVar = unixtime + EPOCH_DIFFERENCE;

    longLongVar = longLongVar*TICKS_PER_SECOND;

    FILETIME ftTime;

    ftTime.dwLowDateTime = (DWORD)longLongVar;
    ftTime.dwHighDateTime = longLongVar >> 32;

    SYSTEMTIME stTime;
    FileTimeToSystemTime(&ftTime, &stTime);
    return stTime;
}

The Parson Library

Parson in a JSON parser which was created by Krzysztof Gabis. I found it suitable for our project as it is light and easy to integrate.

Converting Firefox Date/Time from JSON to CTime

First, we read the date/time from a JSON element, but only use the first 10 (of 13) characters.

C++
double tempnum = json_object_get_number(commit, strDateTime);
string datetime;
datetime = std::to_string(tempnum);
datetime = datetime.substr(0, 10);

Notes

  1. The Parson library provides a function for reading a number as a "double", which is why we first read the date/time into a double variable.
  2. Next, we convert the double into std::string.
  3. We then cut the last 3 digits leaving the length of the string 10 characters.
  4. We call FirefoxTimeToSysTime() sending our string to it.

Converting the SYSTEMTIME into CTime is straight forward:

C++
SYSTEMTIME newtime = utils::FirefoxTimeToSysTime(datetime);
CTime ct(newtime);

We can later display the data in a report or on screen converting the CTime variable into a user friendly date format. In Secured Globe, Inc. we use the following:

C++
#define SG_FRIEDLY_DATEFORMAT L"%d-%m-%Y, %H:%M:%S"

So when we need to use the stored credentials and display one of its elements, we would use:

C++
credentials[i].DateCreated.FormatGmt(SG_FRIEDLY_DATEFORMAT).GetBuffer();

FormatGmt is important if you wish to process data from users in different countries. For local use, the code would be:

C++
credentials[i].DateCreated.Format(SG_FRIEDLY_DATEFORMAT).GetBuffer();

The Firefox Credentials Viewer tool

When you start Firefox Credentials Viewer, a split of a second later, you will see a screen similar to this one. All your stored credentials will be displayed.

You can download this tool from Source Forge.

Image 1

History

  • 30th January, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Secured Globe, Inc.
United States United States
Michael Haephrati is a music composer, an inventor and an expert specializes in software development and information security, who has built a unique perspective which combines technology and the end user experience. He is the author of a the book Learning C++ , which teaches C++ 20, and was published in August 2022.

He is the CEO of Secured Globe, Inc., and also active at Stack Overflow.

Read our Corporate blog or read my Personal blog.





Comments and Discussions

 
QuestionCongratulations und Source Code Pin
PStefano7412-Jun-19 22:41
PStefano7412-Jun-19 22:41 
QuestionGreat article Pin
Member 1355060630-Nov-17 9:02
Member 1355060630-Nov-17 9:02 
AnswerRe: Great article Pin
Michael Haephrati5-Dec-17 9:11
professionalMichael Haephrati5-Dec-17 9:11 
GeneralMy vote of 5 Pin
Perić Željko3-Feb-17 11:27
professionalPerić Željko3-Feb-17 11:27 
QuestionMy vote of 5 Pin
Hans Flocken30-Jan-17 11:34
Hans Flocken30-Jan-17 11:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.