You can download the tool described in this article from here.
This article is the 4rd one 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 2nd one covers Chrome's credentials. The 3rd 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 comparing to previous versions but also comparing 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 per 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.
SHGetSpecialFolderPath(NULL, strAppData, CSIDL_APPDATA, TRUE);
swprintf_s(strIniPath, MAX_PATH, L"%s\\Mozilla\\Firefox\\profiles.ini", strAppData);
GetPrivateProfileString(L"Profile0", L"Path", L"", strRelativePath, MAX_PATH, strIniPath);
swprintf_s(strFullPath, MAX_PATH, L"%s\\Mozilla\\Firefox\\%s", strAppData, strRelativePath);
GetShortPathName(strFullPath, strShortPath, MAX_PATH);
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 intent to use.
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");
Remember to set the Language of your code snippet using the Language dropdown.
Use the "var" button to wrap Variable or class names in <code> tags like
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 know
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.
bool GuessMasterPassword(char *MyGuess)
bool result = FALSE;
PK11SlotInfo *pK11Slot = fpPK11_GetInternalKeySlot();
if (PK11_CheckUserPassword(pK11Slot, MyGuess) == SECSuccess)
result = true;
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).
LPSTR DecryptString(LPSTR strCryptData)
if (strCryptData == 0x0)
LPSTR strClearData = "";
LPBYTE lpBuffer = base64_decode((char*)strCryptData, strlen(strCryptData), (int *)&dwOut);
PK11SlotInfo *pK11Slot = fpPK11_GetInternalKeySlot();
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';
Handling Firefox Date/Time
To be able to process records from various browsers, each of them use 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 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 represent and vice versa.
The code used for our tool intents 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.
SYSTEMTIME FirefoxTimeToSysTime(string FirefoxTime)
__int64 unixtime = atol(FirefoxTime.c_str());
__int64 longLongVar = unixtime + EPOCH_DIFFERENCE;
longLongVar = longLongVar*TICKS_PER_SECOND;
ftTime.dwLowDateTime = (DWORD)longLongVar;
ftTime.dwHighDateTime = longLongVar >> 32;
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.
double tempnum = json_object_get_number(commit, strDateTime);
datetime = std::to_string(tempnum);
datetime = datetime.substr(0, 10);
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:
SYSTEMTIME newtime = utils::FirefoxTimeToSysTime(datetime);
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:
#define SG_FRIEDLY_DATEFORMAT L"%d-%m-%Y, %H:%M:%S"
So when we need to use the stored credentials and display one of it's elements, we would use:
FormatGmt is important if you wish to process data from users in different countries. For local use, the code would be:
The Firefox Credentials Viewer tool
When you start Firefox Credentials Viewer, a split of a second after, you will see a screen similar to this one. All your stored credentials will be displayed.
You can download this tool from Source Forge.