Skip to content

asaix/chrdmp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chrdmp

chrdmp is an offline profile decryption tool for the Google Chrome browser. It enables decryption of the Login Data file that contains user passwords and the Cookies file which contains the browser's cookies. This tool is specifically intended for use with systems that use a keyring to encrypt browser secrets (i.e., for all Linux distributions and NOT for Windows, which uses DPAPI).

Important features:

  • Automatically detects and handles formatting quirks that change depending on the database version.
  • Converts integer column values to text to make their meaning clear.
  • Supports no-keyring setups that use the default secret.

Quick Start

To install, either:

  1. Linux: Download the latest binary from releases.
  2. Other: Clone the source code, install the required packages from requirements.txt, and run the script using Python 3.

chrdmp is a CLI with two subcommands: logins and cookies.

Decrypt passwords

./chrdmp logins -d "Login Data" -o logins.csv -s <secret>

Decrypt cookies

./chrdmp cookies -d "Cookies" -o cookies.csv -s <secret>

Options (same for both commands)

Flag Default Meaning
-d, --db Login Data / Cookies Path to the input SQLite file (must exist)
-s, --secret peanuts "Chrome Safe Storage" keyring secret. Leave default for no-keyring setups
-o, --outfile Required. Output CSV path (overwrites if it exists)

Getting the secret

The "Chrome Safe Storage" keyring secret is trivially obtainable from the target system using API calls run as the user (or possibly other offline/privesc techniques) and can be fed to the program at as a command-line argument. If no keyring was set on the target system, then a secret needn't be provided and the default value "peanuts" will be used.

Placeholders in the output

Some entries can't be decrypted to a normal value. In those cases the output shows a placeholder instead:

  • <EMPTY>: the entry had no value to decrypt (an empty blob).
  • <FAILED: raw value>: decryption failed for that entry. The raw value is included.
  • <SKIPPED: raw value>: the entry was skipped because it needs a non-default secret you didn't provide (see below). The raw value is included.

Skipped entries

Entries that use a randomly generated keyring secret can only be decrypted if you provide that secret. If you leave the secret at its default (peanuts), those entries are skipped instead of decrypted and marked as <SKIPPED: raw value>. The summary at the end counts them under "Skipped (no secret provided but uses non-default secret)". To decrypt them, run the tool again with the correct secret via -s.

Columns in the output CSV

  • logins.csv contains only these columns (shown under friendlier names): origin_url (Origin URL), action_url (Action URL), username_value (Username), password_value (Password), date_created (Date Created), password_type (Password Type), times_used (Times Used), date_last_used (Date Last Used), and date_password_modified (Date Modified). All other columns are omitted as they will likely be irrelevant in nearly every use case. If you require those columns, you can modify the source code to extract columns that might be relevant to your work using the decryption guide below.
  • cookies.csv contains every column from the cookies table, with one exception: the empty value column is dropped, and the decrypted encrypted_value is written in its place under the name value.

License & Disclaimer

This code is distributed under the MIT License. Please note that this tool is meant for authorized use within the limits of the law and the developer(s) are not liable for any illegal or harmful use.

Demo

≻ ./chrdmp cookies -d data/Cookies -s "REDACTED" -o cookies.csv
Extracting cookies using:
  Database: data/Cookies
  Secret: REDACTED
  Output File: cookies.csv

Loading database... 1630 entries loaded. DB version: 24

Summary:
  Successfully decrypted: 1630 entries (0/1630 empty)
  Skipped (no secret provided but uses non-default secret): 0
  Decryption failures: 0

≻ ./chrdmp logins -d data/Login\ Data -s "REDACTED" -o psw.csv
Extracting passwords using:
  Database: data/Login Data
  Secret: REDACTED
  Output File: psw.csv

Loading database... 125 entries loaded.

Summary:
  Successfully decrypted: 125 entries (5/125 empty)
  Skipped (no secret provided but uses non-default secret): 0
  Decryption failures: 0


Decryption Process Explained

On Linux, Chrome protects sensitive files like cookies and passwords using the keyring. Any process run as the user can access the "Chrome Safe Storage" keyring secret, which can then be used to decrypt the files.

This guide walks you through decryption of the Login Data (usernames and passwords) and Cookies files. Obtaining the keyring secret is trivial and can be done through standard system API calls.

This decryption mechanism is common to both Cookies and Login Data, with the only difference being the tables/columns that are referenced in the process.

Before looking at those specific cases, it helps to understand the encryption algorithm in detail.

The Login Data and Cookies files are SQLite databases. The files are not encrypted and can be opened with an SQLite viewer. In fact, most of the fields do not contain encrypted values. However, the usernames, passwords and cookie values are encrypted using the keyring secret.

The secret is 16 random bytes stored in the keyring under the label "Chrome Safe Storage". If a keyring is not available on the system, Chrome uses a hardcoded value of "peanuts" (without the quotes) as the secret. If the blob starts with "v10", then the secret is "peanuts". If it starts with "v11", then it uses a randomly generated keyring secret.

The BLOBs are encrypted/decrypted using AES-128-CBC with a key generated using PBKDF2-HMAC-SHA1 with the keyring secret, a fixed salt "saltysalt" (no quotes), 1 iteration and key length 16.

More precisely,

KEY = PBKDF2-HMAC-SHA1(SECRET, "saltysalt", ITERATIONS=1, DKLEN=16)

To decrypt the blob, we run AES-128-CBC-DECRYPT with key=KEY and IV=" " * 16. The IV is always the same. Before decryption, the blob must be stripped of the version number prefix (v10 or v11). In pseudocode, we can represent this as:

PLAINTEXT = AES-128-CBC-DECRYPT(KEY, IV=" " * 16, DATA=blob[3:])

Note: In the pseudocode above the AES-DECRYPT function does both decryption and PKCS#7 unpadding.

Decrypting the Login Data file

Chrome stores saved login credentials in the logins table of the Login Data file. The table contains a lot of useful information about the saved passwords:

Column Type
origin_url VARCHAR
action_url VARCHAR
username_element VARCHAR
username_value VARCHAR
password_element VARCHAR
password_value BLOB
submit_element VARCHAR
signon_realm VARCHAR
date_created INTEGER
blacklisted_by_user INTEGER
scheme INTEGER
password_type INTEGER
times_used INTEGER
form_data BLOB
display_name VARCHAR
icon_url VARCHAR
federation_url VARCHAR
skip_zero_click INTEGER
generation_upload_status INTEGER
possible_username_pairs BLOB
id INTEGER
date_last_used INTEGER
moving_blocked_for BLOB
date_password_modified INTEGER
sender_email VARCHAR
sender_name VARCHAR
date_received INTEGER
sharing_notification_displayed INTEGER
keychain_identifier BLOB
sender_profile_image_url VARCHAR
date_last_filled INTEGER
actor_login_approved INTEGER

password_value is the only encrypted field and can be decrypted using the method described above.

The password type field stores integers that map to the following:

Value Meaning
0 Form submission
1 Generated
2 Credential API
3 Manually added
4 Imported
5 Received via sharing
6 Imported via credential exchange
7 Change submission

The date fields store the time in microseconds since 1601-01-01.

Other fields are self-explanatory and unencrypted.

Decrypting the Cookies file

The cookie data is stored in the cookies table in the Cookies file.

The table lists all the information Chrome stores about the cookies:

Column Type
creation_utc INTEGER
host_key TEXT
top_frame_site_key TEXT
name TEXT
value TEXT
encrypted_value BLOB
path TEXT
expires_utc INTEGER
is_secure INTEGER
is_httponly INTEGER
last_access_utc INTEGER
has_expires INTEGER
is_persistent INTEGER
priority INTEGER
samesite INTEGER
source_scheme INTEGER
source_port INTEGER
last_update_utc INTEGER
source_type INTEGER
has_cross_site_ancestor INTEGER

encrypted_value is the only encrypted field and stores the value of the cookie.

The date fields store the time in microseconds since 1601-01-01.

It can be decrypted using the method described above. There is one caveat: on databases version 24 and up, the plaintext value is prefixed by a 32-byte metadata field.

I.e., to obtain the cookie value,

if db_version >= 24:
    plaintext = plaintext[32:]

Several of the unencrypted integer columns are enums or boolean flags. They map to the following human-readable values:

Column Value Meaning
is_secure, is_httponly, is_persistent, has_expires, has_cross_site_ancestor 0 no
1 yes
priority 0 low
1 medium
2 high
samesite -1 unset
0 none
1 lax
2 strict
source_scheme 0 unset
1 http
2 https
source_type 0 unknown
1 http header
2 script
3 other