Click here to Skip to main content
15,867,686 members
Articles / Security

The Secrets of Google Chrome Credentials

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
30 Jan 2017CPOL6 min read 35.4K   1K   30   15
Chrome stores all passwords and other credentials in an encrypted database but guess what: they can be retrieved by anyone with the proper knowledge. This article will show you how.
This article covers Google Chrome and how credentials are stored and how they can be fetched from it.

Introduction

This article is one of several articles covering the secrets of obtaining stored (and encrypted) credentials stored by browsers (and other applications, for example: MS Outlook). The first article covered Wi-Fi credentials. This article covers Google Chrome and how credentials are stored and can be fetched from it.

The Profile Folder

Chrome stores the user’s credentials inside a special folder called the “profile folder”. The first step would be understanding where to find that folder. To understand better, note that Chrome has a built in mechanism for displaying important information about its version and installation location. To view this information, just type: "chrome://version/" in the Address Bar.

Image 1

Among the many pieces of information displayed, please refer to "Profile Path", which is where the sensitive data is kept.

To get this path programmatically, we need to do as follows:

C++
#define FORENSICS_CHROMECREDENTIALS_PATH _T("\\Google\\Chrome\\User Data\\Default\\")

bool result = false;
TCHAR szProfileFolderPath[MAX_PATH];
result = SHGetSpecialFolderPath(0, szProfileFolderPath, CSIDL_LOCAL_APPDATA, 0);
StrCat(szProfileFolderPath, FORENSICS_CHROMECREDENTIALS_PATH);

First, we obtained the user specific path of his or her Windows' user account. That can be c:\users\john\ or c:\users\myself\, and since we don't know it, we don't use any hardcoded value but obtain it during runtime.

The second part is the relative path of the Google data, which is constant so we do keep that part hardcoded. When we combine the two, we get the path.

Now that we have the path, we need to focus in one specific file which is in fact a SQLite3 database: Login Data.

To get that file, we add "\" (_T("\\") to the path and then the string _T("Login Data") and when we do, szProfileFolderPath will hold the full path of the database we need to open.

C++
#define FORENSICS_CHROMECREDENTIALS_DB _T("\\Login Data")
StrCat(szProfileFolderPath, FORENSICS_CHROMECREDENTIALS_DB);

Before we open this database, it is advised to copy it to another file so it won't intervene with any instance of Google Chrome currently opened, and by doing so, there is no need to shut down Chrome before we operate.

C++
#define TEMP_CHROME_DB    _T("temp.db")
CopyFile(szProfileFolderPath, TEMP_CHROME_DB, FALSE);

Some Notes about SQLite3

During the day to day development work at Secured Globe, Inc. we use SQLite3 a lot. Most of the forensics information out there is associated one way or another with SQLite3. Sqlite3 can be used at the source code level (adding sqlite3.c and sqlite3.h to your program, or as a static / dynamic library).

We use it with two additional enhancements:

  • CppSqlite3 - a wrapper which can ensure better handling with UNICODE test (without it, sqlite3 can hardly deal with international characters within its databases). The first versions were published here at Code Project.
  • SEE - a paid library ($2,000 per license) sold by Sqlite3 which allows an application to read and write encrypted database files. Four different encryption algorithms are supported:
    • RC4
    • AES-128 in OFB mode
    • AES-128 in CCM mode
    • AES-256 in OFB mode

The following article is very handy when it comes to helping people using Sqlite3 in their programs, and especially Windows programs.

Fetching the Credentials from the SQLite3 Database

Next, we open the database and run a query on the specific table we need for the stored credentials. This table is called "logins". We predefine the query to be executed on this table as follows:

C++
#define CHROME_CRED_SQL_QUERY "SELECT signon_realm,username_value,
password_value,date_created FROM logins"

Then, we can open the database and run this query:

C++
CppSQLite3DB CredentialsDB; // we define a CppSQLite3DB object
try
{
    CredentialsDB.open(TEMP_CHROME_DB);
}
catch (CppSQLite3Exception &e)
{
    // Handle exceptions here
    return false;
}
CppSQLite3Query SqlQuery;
CString sql;
sql = CHROME_CRED_SQL_QUERY;
try
{
    SqlQuery = CredentialsDB.execQuery(sql);
}
catch (CppSQLite3Exception &e)
{
    // Handle query execution's exceptions here
    return 0;
}
int count = 0;
int size = 0;

The SGBrowserCredentials Data Structure

The SGBrowserCredentials (Secured Globe Browser Credentials) is used for any process of fetching browser credentials and is capable of holding the relevant fields which are common to all browsers.

We define the single element and a CSimpleArray for the purpose of collecting the results of our program. We also use CTime for the date/time stamp of each entry. We do so to be able to compare credentials from different sources (browsers), as each browser use a different method for storing date and time. The importance of date/time for the scope of our program is to be able to use it later for filtering the results. For example: being able to tell which new credentials were created since 1.1.2017 or since the last time we checked.

C++
typedef struct _SGBrowserCredentials
{
    int Browser; // 0 = chrome, 1 = ie, 2 = firefox, 
    TCHAR Site[256];
    TCHAR UserName[80];
    TCHAR Password[256];
    CTime DateCreated;
    _SGBrowserCredentials()
    {
        Site[0] = 0;
        UserName[0] = 0;
        Password[0] = 0;
        DateCreated = NULL;
    }
} SGBrowserCredentials;

typedef CSimpleArray<SGBrowserCredentials> SGBrowserCredentialsArray;

Reading the Data

After running the SQL query, we should expect to get a number of records. Each record is a single entry such as a stored credentials. We use the following local variables:

C++
WCHAR *Site, *User, *CreationDate;

DATA_BLOB DataIn, DataOut;

to store a single record. We read also encrypted data which we will decrypt later.

C++
#define CHROME_DB_FIELD_SITE 0
#define CHROME_DB_FIELD_USER 1
#define CHROME_DB_ENC_FIELD_PASS 2
#define CHROME_DB_FIELD_DATE 3

Then the loop we run over the results looks like this:

C++
while (!SqlQuery.eof())
{
    Site = (WCHAR *)SqlQuery.fieldValue(CHROME_DB_FIELD_SITE);
    User = (WCHAR *)SqlQuery.fieldValue(CHROME_DB_FIELD_USER);
    DataIn.pbData = (LPBYTE)SqlQuery.getBlobField(CHROME_DB_ENC_FIELD_PASS, size);
    DataIn.cbData = size;
    CreationDate = (WCHAR *)SqlQuery.fieldValue(CHROME_DB_FIELD_DATE);
...

Now we need to decrypt the encrypted part and that can be done smoothly as long as you run the program from where the database was originally stored. The reason for that is that the encryption is based on the Windows logon system. If you copy the database and try to open it from another machine, you won't be able to decrypt the password but just to see the other fields.

Decrypting Encrypted Data

To decrypt the data, use CryptUnprotectData which decrypts password (in a DATA_BLOB structure).

C++
bool bDecrypted = CryptUnprotectData(&DataIn, 0, 0, 0, 0, 8, &DataOut);

If it has succeed, we will have the decrypted password in DataOut.

Handling Chrome's Date/Time Format

Before we create the single record and add it to our dynamic array, we need to interpret the way date and time of each entry are kept by Chrome. It would be easiest to convert the date/time (fetched as string from the database) into a FILETIME object. The FILETIME structure contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). First, we need to grab the first 10 digits of the long number used by Chrome and store it in a ULONGLONG variable (using _wcstoui64). Then we multiple it by 10 and assign the "LowPart" and "HighPart" to the FILETIME object.

C++
ULONGLONG lltm = _wcstoui64(ChromeTime.GetString(), NULL, 10);
ULARGE_INTEGER uLarge;
uLarge.QuadPart = lltm * 10;
FILETIME ftTime;
ftTime.dwHighDateTime = uLarge.HighPart;
ftTime.dwLowDateTime = uLarge.LowPart;

From FILETIME we can always convert to SYSTEMTIME and to CTime easily.

The Program

When you start the program, you will see all stored credentials on your machine. It should look like this:

Image 2

The program and any updates will be available at www.windowscredentials.com and at Source Forge.

About the Source Code

The source code can be useful for demonstrating not only the functionality described in the article, but some GUI (Graphical User Interface) aspects. The source code project is a Dialog based MFC one, built using Visual Studio Ultimate 2013. Word of thanks should go to Marc Richarme who created EasySize. His class is used for supporting resizing the dialog while preserving the relative position of the controls it contains. I have used TabCtrlSSL (thanks Derek Lakin) with changes and enhancements we have made. I worked on displaying the browser's icon (Chrome, in this case) in the grid, while displaying it with a transparent color. All images to be shown transparent in the grid (which is in fact a CListCtrl) need to have a common background color (Green / RGB(0,255,0) in my case) and should be saved as a 24 bit BMP file. That's basically the trick. You may also learn from the source code about displaying labels and other controls whilst keeping a common background color to the entire dialog.

* The graphics are copyrighted to Secured Globe, Inc. and should not be used for other purposes / products.

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

 
QuestionDose not work on new versions of chrome Pin
Shahyar Esmaili14-Aug-21 0:26
Shahyar Esmaili14-Aug-21 0:26 
AnswerRe: Dose not work on new versions of chrome Pin
Michael Haephrati14-Aug-21 3:49
professionalMichael Haephrati14-Aug-21 3:49 
I will check...
- Michael Haephrati מיכאל האפרתי

AnswerRe: Dose not work on new versions of chrome Pin
Michael Haephrati16-Aug-21 10:27
professionalMichael Haephrati16-Aug-21 10:27 
Questioncompile on Mac Pin
Member 1471838816-Jan-20 5:02
Member 1471838816-Jan-20 5:02 
QuestionAny know issue with the source code? Pin
arut jothi3-Feb-17 8:19
arut jothi3-Feb-17 8:19 
AnswerRe: Any know issue with the source code? Pin
Michael Haephrati3-Feb-17 10:13
professionalMichael Haephrati3-Feb-17 10:13 
GeneralRe: Any know issue with the source code? Pin
arut jothi3-Feb-17 11:34
arut jothi3-Feb-17 11:34 
GeneralRe: Any know issue with the source code? Pin
Michael Haephrati3-Feb-17 11:47
professionalMichael Haephrati3-Feb-17 11:47 
GeneralRe: Any know issue with the source code? Pin
arut jothi6-Feb-17 4:43
arut jothi6-Feb-17 4:43 
GeneralRe: Any know issue with the source code? Pin
arut jothi6-Feb-17 5:55
arut jothi6-Feb-17 5:55 
QuestionSource code ... Pin
Richard MacCutchan30-Jan-17 22:24
mveRichard MacCutchan30-Jan-17 22:24 
AnswerMessage Closed Pin
1-Feb-17 0:50
professionalMichael Haephrati1-Feb-17 0:50 
GeneralRe: Source code ... Pin
Richard MacCutchan1-Feb-17 1:10
mveRichard MacCutchan1-Feb-17 1:10 
GeneralRe: Source code ... Pin
Michael Haephrati1-Feb-17 1:20
professionalMichael Haephrati1-Feb-17 1:20 
GeneralMy vote of 5 Pin
Hans Flocken30-Jan-17 11:37
Hans Flocken30-Jan-17 11:37 

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.