Click here to Skip to main content
13,736,547 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

10.6K views
11 bookmarked
Posted 30 Jan 2017
Licenced CPOL

The Secrets of Firefox Credentials

, 30 Jan 2017
Rate this:
Please Sign up or sign in to vote.
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.

You can download the tool described in this article from here.

Introduction

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. 

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 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 this.

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;
    }
    (*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).

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 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;

    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.

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:

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:

#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:

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:

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

 

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

 

License

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

Share

About the Author

Michael Haephrati
CEO Secured Globe, Inc.
United States United States
Michael Haephrati, CEO and co-founder of Secured Globe, Inc. Worked on many ventures starting from HarmonySoft, designing Rashumon, the first Graphical Multi-lingual word processor for Amiga computer. During 1995-1996 he worked as a Contractor with Apple at Cupertino.



You may also be interested in...

Comments and Discussions

 
QuestionGreat article Pin
30-Nov-17 9:02
member30-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
memberHans 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.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180920.1 | Last Updated 30 Jan 2017
Article Copyright 2017 by Michael Haephrati
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid