Online Credit Card Theft: Today’s Browsers Store Sensitive Information Deficiently, Putting User Data at Risk



March 13, 2018 | | Avi Gimpel

Credit card theft continues to rise in today’s chip era. It’s difficult to take advantage of a card’s chip security online, and attackers are leveraging various vectors to access credit card details.

Man-in-the-middle (MITM), malware and rootkit attacks are growing in popularity. Attackers are also using remote/local exploitation to steal data. Once attackers gain access to data, they transfer stolen credit card details to their drop zone servers, and then use it for anonymous payments or sell it to make a profit.

This research peeks behind the online retail curtain to examine how the four most popular browsers – Internet Explorer (IE), Microsoft Edge, Google Chrome and Mozilla Firefox – store credit card data, and the associated risks with each.

We attempt to answer often-asked questions such as whether browsers are secure enough to be trusted with credit card data; how and where credit card information is saved online; and ultimately, what consumers and organizations should do to protect their data.

AutoFill and AutoComplete Features
Today’s browsers enable the preservation of user information – including credit card data – as an added layer of convenience for the user. But they also raise some security concerns.

Let’s first look at the “AutoFill” and “AutoComplete” features to understand how they work. Browsers can store HTML form data and automatically fill the appropriate form fields when information is requested. This saves the user from retyping the details, and speeds the process of filling out online forms.

IE, Edge, Chrome and Firefox all invoke this AutoFill feature. Unfortunately, they store sensitive information in a deficient way.

In figure 1, you can see an example of the AutoFill feature.

Figure 1-AutoFill feature

Mapping the AutoFill Storage

AutoFill data is stored in different locations based on the operating systems (OS). Let’s map the locations.

IE and Edge store AutoFill data in values under the following registry keys-
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\FormData
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage1
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2

Chrome stores data in a SQLite database file-

%LocalAppData%\Google\Chrome\User Data\Default\Web Data

Firefox stores data in a SQLite database file-


It is important to mention that IE, Edge, Chrome and Firefox leverage Windows DPAPI (Data Protection Application Programming Interface) to encrypt the AutoFill data before storing, and decrypt it before the next usage.

DPAPI Clarification

DPAPI is a pair of function calls that provide operating system-level data protection services to user and system processes. By data protection, we mean a service that provides confidentiality of data by using encryption. Because data protection is part of the operating system, every application can now secure data without needing any specific cryptographic code other than the necessary function calls to DPAPI. These calls are two simple functions with various options to modify DPAPI behavior.

The problem is that browsers use the DPAPI in the user context, while encrypting the required data, without the need of user intervention or additional passwords. Any script or code can run in the same user context – not requiring special permission or elevation – and reverse the DPAPI process by calling to the decryption DPAPI function, and later decrypt the encrypted data – just as the browsers do.

There is a way to use DPAPI in a more secure way, which requires user intervention at the decryption process, which we’ll discuss later.

As for Firefox, it saves the AutoFill data completely unencrypted. In this research, we focus only on credit card assets, but there is other sensitive data – such as passwords, user names, secret links and more – that’s stored under the same file/registry value that holds the AutoFill data.

Secret Data Extraction

In order to extract the credit card data from IE, Edge, Chrome and Firefox, we need to understand two things:

  • SQLite database structure
  • How to use DPAPI in order to decrypt the credit card details

SQLite is a popular choice as embedded database software for local/client storage in application software such as web browsers. It is arguably the most widely deployed database engine, as it is used today by several widespread browsers, operating systems, embedded systems (such as mobile phones) and others. SQLite has bindings to many programming languages.

DPAPI CryptUnprotectData function

Figure 2-CryptUnprotectData description (MSDN)

The important parameters-

pDataIn [in]
A pointer to a DATA_BLOB structure that holds the encrypted data.

ppszDataDescr [out, optional]
A pointer to a string-readable description of the encrypted data.

pOptionalEntropy [in, optional]
A pointer to a DATA_BLOB structure that contains a password or other additional entropy used when the data was encrypted.

pPromptStruct [in, optional]
A pointer to a CRYPTPROTECT_PROMPTSTRUCT structure that provides information about where and when prompts are to be displayed and what the content of those prompts should be. This parameter can be set to NULL.

pDataOut [out]
A pointer to a DATA_BLOB structure that receives the decrypted data.

Chrome Case Study for Secrets Extracting

Chrome SQLite storage file

Figure 3 shows the AutoFill data of Chrome (under the Web Data SQLite file) by using the “DB Browser for SQLite” tool.

Note that Chrome saves the credit cards details in a separate table, named “credit_cards”

Figure 3-Chrome AutoFill credit_cards details

As you see, all the details are in cleartext, except the card_number field, which is stored as an encrypted BlobData.

In figure 4 you can see the other AutoFill tables, the data in those is saved unencrypted.

Figure 4-Chrome complete AutoFill data

Chrome DPAPI call 

Chrome allows users to see the stored credit cards by using the settings menu, or by going to-

Figure 5-Chrome Setting/viewing credit cards GUI option

As you see, we have a stored card with the following number- “4916 4182 7187 7549.” While asking to see credit card details, or whenever the browser tries to AutoFill a form’s fields, the DPAPI function for decrypting data is called.

In figure 6 you can see Chrome API calls to the DPAPI function -CryptUnProtectData(). The parameter pDataOut->pbdata points to the returned decrypted data (see again the function declaration and the pDataOut parameter).

*You can see the card number “4916 4182 7187 7549” in the address space of pDataOut->pbdata.

Figure 6- API monitor, Chrome call for the DPAPI CryptUnprotectData() function

Corresponding to that, IE and Edge browsers use the same procedure when attempting to AutoFill the user forms fields.

The only difference is that IE and Edge store their AutoFill data over the registry as an encrypted BlobData and without any known order (unlike those browsers that use the SQLite db).

As for Firefox, you can also use the “DB Browser for SQLite” tool to see the unencrypted AutoFill data.

Deep Diving into the Extraction Code

After understanding the decryption subject, all we have left to do in our POC is:

  1. Import the package that deals with SQLite db (relevant for Chrome and Firefox) and DPAPI into our project.
  2. Use the DPAPI function in order to decrypt the browsers’ AutoFill BlobData.

Let’s start.

 Chrome Code (C#)-

Line 1-Defines the path to the Chrome AutoFill db file (Chrome should be closed in order to have an access to the file).
Line 2-Defines the name of the table which stores the credit cards’ details.

string SQLiteFilePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+ "\\Google\\Chrome\\User Data\\Default\\Web Data";
string tableName = "credit_cards";
. . .

Lines 1-5 define the connection to the db, and the query (command) to the required table (credit_cards).
Lines 7-8 return the required data into DB DataTable object (this object represents one table of in-memory data).

string ConnectionString = "data source=" + SQLiteFilePath + ";New=True;UseUTF16Encoding=True";
string sql = string.Format("SELECT * FROM {0} ", tableName);
SQLiteConnection connect = new SQLiteConnection(ConnectionString)
SQLiteCommand command = new SQLiteCommand(sql, connect);
SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);

DataTable DB = new DataTable();
. . .

Line 1 extracts the encrypted BlobData field (the credit card number) from the DB object.
Line 2 sends the encrypted BlobData for decryption.
(DPAPI.Decrypt() is just a wrapper function for the CryptUnProtectData() call)

byte[] byteArray = (byte[])DB.Rows[i][4];
byte[] decrypted = DPAPI.Decrypt(byteArray, entropy, out description);
. . .

IE & Edge code (C++)-

Line 1 defines a DATA_BLOB object, this object will hold the encrypted data (AutoFill reg values).
Line 2 defines a DATA_BLOB object, this object will hold the decrypted data (AutoFill reg values).

Lines 4-8 define the reg keys. (Those reg keys are holding the reg values, which are holding the AutoFill Blob Data).

DATA_BLOB DataVerify;

std::vector<LPCWSTR> RegKeys;
RegKeys.push_back(L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\FormData");
RegKeys.push_back(L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\microsoft.microsoftedge_8wekyb3d8bbwe\\MicrosoftEdge\\IntelliForms\\FormData");
RegKeys.push_back(L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage1");
RegKeys.push_back(L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2");
. . .

What’s left to do is run over every reg key, and for each reg key to extract its reg values (AutoFill BlobData).

for (int i = 0; i < 4; i++) // run as number of keys
//run over the RegKeys keys
RegOpenKeyEx(HKEY_CURRENT_USER, RegKeys[i], 0, KEY_QUERY_VALUE, &hKey)

//run over each key’s values and extracting the reg value (BlobData)
for (int j = 0; j < keyValues.size(); j++)
RegQueryValueEx(hKey, keyValues[j].c_str(), 0, 0, (LPBYTE)dwReturn, &dwBufSize);
. . .

In order to send the data to the decryption function (decryptContentDPAPI is a wrapper function to the CryptUnProtectData() function), we need to warp the return AutoFill BlobData (which got by the RegQueryValueEx call) into a DATA_BLOB object. The decrypted data will be returned into the DataVerify object.

DataIn.cbData = dwBufSize;
DataIn.pbData = dwReturn;
. . .

Here’s a video that demonstrates the complete attack:


The problem is that malware and trojans can run in the same user context as the browsers that store users’ credit card information, giving them the ability to extract the most secret user data, such as credit card data and passwords. The root of the problem is that the usage of DPAPI does not require any user intervention (asking for a passphrase) while automatically decrypting the secret data.

One solution that’s relevant for browser developers is for browsers to ask for a passphrase in addition to the default local sources that DPAPI uses to encrypt/decrypt data when encrypting the secret data. When the browser decrypts the data to AutoFill or to show the credit card details, it would then ask for the identical passphrase from the user.

DPAPI provides the option for that passphrase usage. This option is enabled by setting up the pOptionalEntropy parameter when encrypting/decrypting the data using the CryptProtectData() / CryptUnProtectData() functions.


So what should consumers do to protect their online credit card information?

First, they should disable their AutoFill browser options and clean the current AutoFill stored data.

Second, they should also refrain from storing credit card data manually. Sure, this eliminates the convenience of not having to type in credit card information every time a consumer wants to make an online purchase, but it also eliminates the security risks associated with stored browser data.



Share This