Chrome Tips

From bibbleWiki
Jump to navigation Jump to search

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

# does not work anymore
# pip3 install pycrypto
pip3 install pycryptodome

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.